perm filename PARSE.SAI[HAL,HE]4 blob
sn#245661 filedate 1976-11-03 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00062 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00005 00002 UPDATES TO PARSE BY MSM (THERES MORE ON THIS PAGE AND MSM SWITCHES)
C00009 00003 ! reserved word classes
C00011 00004
C00013 00005 ! miscellaneous reserved words
C00014 00006 ! dec_name, declaration names for input and output
C00016 00007 ! operators
C00021 00008 ! reserved_words
C00027 00009 ! init_reserved
C00029 00010 ! predefined constants
C00031 00011 ! compiler switches and control tables
C00034 00012 ! hash, declaration of debugging variables, start of hidden_parse
C00037 00013 ! ---- DECLARATIONS ----
C00043 00014
C00045 00015
C00046 00016 ! error, error_reject, print, file_indent
C00052 00017 ! read, push_macro_delimiters
C00056 00018 ! mac_test_and_expand
C00060 00019 ! get_token
C00063 00020 ! look for reserved word
C00066 00021 ! check
C00068 00022 ! combine
C00072 00023 ! reduce, tmake_R
C00074 00024 ! vmake_R, fmake_R
C00077 00025 ! vvtrans_R, sneg_R
C00080 00026 ! rinv_R, sabs_R
C00082 00027 ! plus_R
C00085 00028 ! minus_R
C00088 00029 ! times_R
C00092 00030 ! rot_R, wrt_R
C00095 00031 ! →_R
C00097 00032 ! reduce execution starts here
C00102 00033 ! printexpr
C00103 00034 ! p_exp2
C00105 00035 ! parse_special
C00111 00036 ! p_exp2 execution begins here, p_exp
C00118 00037 ! P_condition
C00121 00038 ! P_clauses, T_gen
C00131 00039 ! P_statement, begin_P
C00133 00040 ! cobegin_P, end_P, open_paren_P
C00136 00041 ! declare_P
C00140 00042 ! global_P
C00143 00043 ! if_P, plan_P, while_P
C00145 00044 ! for_P
C00147 00045 ! move_P
C00149 00046 ! affix_p
C00153 00047 ! unfix_P, signal_P
C00156 00048 ! wait_P
C00157 00049 ! when_P
C00160 00050 ! dump_P
C00162 00051 ! assert_P
C00166 00052 ! on_P, reference_P, parseshit_P, open_P
C00169 00053 ! center_P, stop_P
C00171 00054 ! define_P
C00176 00055 ! require_P
C00179 00056 ! dimension_P
C00184 00057 ! abort_P
C00186 00058 ! P_statement execution starts here
C00192 00059 procedure process_switches(record_pointer(file) F)
C00195 00060 ! execution starts here
C00197 00061 ! set up input and output
C00203 00062 ! set up predefined constants and variables
C00207 ENDMK
C⊗;
COMMENT UPDATES TO PARSE BY MSM (THERES MORE ON THIS PAGE AND MSM SWITCHES)
11-2-76 CHANGE LABEL TO STMLAB ON PG 6
11-2-76 CHANGES TO DECLARE_P TO allow default of distance to frames
11-2-76 LN49 PG 24 ADDED TO GIVE DIMENSION OF FRAME AS DISTANCE
11-2-76 ADDED ELSE DIM←0 AFTER SECOND IF STATEMENT TO CURE BUG ON PG 41 DECLARE_P
11-1-76 WOBBLE COMMAND IMPLEMENTED
10-29-76 LOGGING FEATURE IMPLEMENTED
10-27-76 TVSUB AND VSUB IMPLEMENTED
10-18-76 CHANGE STOP BLUE OR YELLOW TO STOP BARM OR YARM;
comment the AL to S-expression translator AND MSM SWITCHES;
Begin "PARSE"
REQUIRE 1024 STRING_PDL; REQUIRE 1024 STRING_SPACE; REQUIRE 1024 SYSTEM_PDL;
require "[][]" delimiters;
define
α =[begin],
β =[end],
! =[comment],
tab ='11,
lf ='12,
ff ='14,
cr ='15,
space ='40,
dquote ='42,
rubout ='177,
crlf =[('15&'12)],
hasher =256,
preload_array(name, defs, type, first, len)=[
preload_with defs null; type array name[first:first+len] ];
! N.B. -- preload_array always creates an array 1 longer than requested;
! if /nB is set in the command line then assume he wants a debugging parser;
require "<><>" delimiters;
ifc ¬declaration(debug_compile) thenc
define
decipher_debug(a)=<
assignc a=cvms(compiler!banner)[2 to ∞-1];
assignc a=cvps(a)[length(scanc(cvps(a), lf, null, "IA"))+1 for ∞];
assignc a=cvps(a)[length(scanc(cvps(a), tab, null, "IA"))+1 for ∞];
assignc a=cvps(a)[length(scanc(cvps(a), space, null, "IA"))+1 for 1];
"a">;
ifc decipher_debug()="0"
thenc define debug_compile=false;
elsec define debug_compile=true;
endc
endc
require unstack_delimiters;
require ifc ¬debug_compile
thenc " NON-" elsec " " endc & "DEBUGGING VERSION " message;
ifc debug_compile thenc EXTERNAL PROCEDURE BAIL; endc
define
indices(name, postfix)=[
redefine xxcount=0;
redefine xx(xxarg)=[
redefine xxtemp=[define xxarg] & [postfix=xxcount];
xxtemp;
redefine xxcount=xxcount+1;];
name];
! ID postfix conventions
_VALUE AL data types
_RES reserved word types
_beg reserved word group begin
_end reserved word group end
_R REDUCE action routines
_P PARSE action routines
_TOKEN scanner token types
_CM condition monitors
_X indices of various sorts
_METRIC dimensional analysis non-sense
_DIMEN how to combine various matrix operands
;
! **********; require "SNAILR[HAL,HE]" source_file; ! **********;
DEFINE MSMCHECK = "TRUE"; ! used on pg 58;
! reserved word classes;
redefine xx(str)=[
redefine reserved_X_count=reserved_X_count+1;
redefine xx_temp="define " & "str" & "_RES=reserved_X_count";
xx_temp;];
define statement_definitions=[
XX(BEGIN)
XX(COBEGIN)
XX(END) ! also includes semicolon and COEND;
XX(OPEN_PAREN)
XX(DECLARE)
XX(GLOBAL)
XX(IF)
XX(PLAN)
XX(WHILE)
XX(FOR)
XX(MOVE)
XX(AFFIX)
XX(UNFIX)
XX(SIGNAL)
XX(WAIT)
XX(WHEN)
XX(DUMP)
XX(ASSERT) ! also DENY;
XX(ON)
XX(REFERENCE)
XX(PARSESHIT)
XX(OPEN) ! also CLOSE;
XX(CENTER)
XX(STOP)
XX(DEFINE)
XX(REQUIRE)
XX(DIMENSION) ! also COMMENT;
XX(ABORT) ! also PRINT;
];
define operator_classes=[
xx(comma) ! order of this group determines arithmetic precedence;
xx(or)
xx(and)
xx(not)
xx(order)
xx(abs)
xx(add)
xx(mult)
xx(trans)
xx(vector)
xx(close_paren)
];
define require_definitions=[
xx(SOURCE_FILE)
xx(DELIMITERS)
xx(UNSTACK_DELIMITERS)
xx(REPLACE_DELIMITERS)
];
define move_definitions=[
xx(VIA)
xx(WITH)
xx(ARRIVAL)
xx(WOBBLE)
];
! All reserved word class id's have a postfix of "_RES". The fact that the parser
groups clases together is reflected by the definition of id's with "_beg" and
"_end" postfixes. The code demands that misc_RES be 0;
define
brace_RES =-1,
misc_RES =0,
cm_RES =0,
reserved_X_count=0,
statement_beg =reserved_X_count+1;
statement_definitions;
define
statement_end =reserved_X_count,
operator_beg =reserved_X_count+1;
operator_classes;
define
operator_end =reserved_X_count,
move_beg =reserved_X_count+1;
move_definitions;
define
move_end =reserved_X_count,
require_beg =reserved_X_count+1;
require_definitions;
define
require_end =reserved_X_count+1;
XX(METRIC) ! TIME, DISTANCE, etc.;
indices(require_definitions, _X);
indices(move_definitions, _X);
! miscellaneous reserved words;
define metric_definitions=[
xx(nil)
xx(DISTANCE)
xx(TIME)
xx(MASS)
xx(ANGLE)
];
indices(metric_definitions, _METRIC);
define
metric_max =xxcount-1;
! condition monitors;
define cm_definitions=[
xx(nil)
xx(FORCE)
xx(TORQUE)
xx(FORCE_OR_TORQUE)
xx(DURATION) ! this and subsequent entries are zero in reserved words;
xx(TEMPERATURE)
xx(SQUEEZE)
];
indices(cm_definitions, _CM);
! dec_name, declaration names for input and output;
! don't juggle the order of these definitions, because the parse will cease to
function;
define dec_name_definitions=[
xx(SCALAR, SVAR)
xx(VECTOR, VVAR)
xx(ROT, RVAR)
xx(FRAME, FVAR)
xx(PLANE, PVAR)
xx(TRANS, TVAR)
xx(EVENT, EVAR)
xx(ATOM, ATOM)
xx(WORLD, WVAR)
xx(CM_LABEL, ONLAB)
xx(CLC_LABEL, CLCLAB)
xx(CH_LABEL, CHGLAB)
xx(LABEL, STMLAB)
];
! data types;
DEFINE
form_VALUE =-1,
boole_VALUE =0; ! others follow directly;
define
dec_name_count=0;
redefine xx(in, out)=[
redefine dec_name_count=dec_name_count+1;
redefine xx_temp="define in" & "_VALUE=" & cvms(dec_name_count);
xx_temp;];
dec_name_definitions;
define frame_exp_VALUE=trans_VALUE; ! COERCION DICTATES THAT THESE BE THE SAME;
redefine xx(in, out)=["out",];
preload_array(
dec_name, dec_name_definitions, string, 1, dec_name_count);
! operators;
! ********** WARNING!!!!! **********
keep all entries marked TRUE contiguous
don't disturb the order of this table ;
define operator_definitions=[
XX(NOT, 1, FALSE, boole, boole, ignore)
XX(AND, 2, FALSE, boole, boole, ignore)
XX(OR, 2, FALSE, boole, boole, ignore)
XX(SEQ, 2, FALSE, boole, scalar, ignore)
XX(SNE, 2, FALSE, boole, scalar, ignore)
XX(SGT, 2, FALSE, boole, scalar, ignore)
XX(SLT, 2, FALSE, boole, scalar, ignore)
XX(SGE, 2, FALSE, boole, scalar, ignore)
XX(SLE, 2, FALSE, boole, scalar, ignore)
XX(UVECT, 1, FALSE, vector, vector, same)
XX(AXIS, 1, FALSE, vector, rot, ignore)
XX(POS, 1, FALSE, vector, trans, ignore)
XX(ORIENT, 1, FALSE, rot, trans, ignore)
XX(TMAKE, 2, TRUE, trans, boole, ignore)
XX(VMAKE, 3, TRUE, vector, scalar, ignore)
XX(FMAKE, 2, TRUE, trans, boole, ignore)
XX(VVTRANS, 3, TRUE, trans, scalar, ignore)
XX(SNEG, 1, TRUE, scalar, scalar, same)
XX(RINV, 1, TRUE, scalar, scalar, inverse)
XX(SABS, 1, TRUE, scalar, scalar, same)
XX([+], 2, TRUE, scalar, scalar, check, PLUS)
XX([-], 2, TRUE, scalar, scalar, check, MINUS)
XX([*], 2, TRUE, scalar, scalar, multiply, TIMES)
XX(WRT, 2, TRUE, scalar, scalar, multiply)
XX(ROT, 2, TRUE, vector, boole, ignore)
XX(→, 2, TRUE, trans, boole, divide)
XX(VDOT, 2, FALSE, scalar, vector, multiply)
XX(ANGLE, 2, FALSE, scalar, vector, ignore)
XX(VCROSS, 2, FALSE, vector, vector, multiply)
XX(VVROT, 2, FALSE, rot, vector, ignore)
XX(SDIV, 2, FALSE, scalar, scalar, divide)
XX(STOS, 2, FALSE, scalar, scalar, ignore)
XX(NOMV, 1, FALSE, form, form, same)
];
define
first_true_op=-1,
op_count=0;
redefine xx(str1, i1, boole, i2, i3, i4, str2)=[
redefine op_count=op_count+1;
ifc "str2"=null
thenc redefine xxtemp=[define str1] & "_X=op_count";
elsec redefine xxtemp=[define str2] & "_X=op_count";
endc
xxtemp;
ifc first_true_op<0 and boole
thenc redefine first_true_op=op_count; endc];
operator_definitions;
define zap_op(name, type, arg, postfix)=[
ifc "postfix"=null
thenc redefine xx(str1, i1, boole, i2, i3, i4, str2)=[arg,];
elsec redefine xx(str1, i1, boole, i2, i3, i4, str2)=
[arg]&[postfix,];
endc
preload_array(name, operator_definitions, type, 1, op_count)];
zap_op(
op_array, string, "str1");
zap_op(
op_num, integer, i1);
zap_op(
op_bool, boolean, boole);
zap_op(
result_type, integer, i2, _VALUE);
zap_op(
type_of_args, integer, i3, _VALUE);
! specifies how to work out new DIMENSION of argument ;
define
ignore_dimen =0,
same_dimen =1,
inverse_dimen =2,
check_dimen =3,
multiply_dimen =4,
divide_dimen =5;
zap_op(
dimen_changes, integer, i4, _dimen);
! reserved_words;
define reserved_definitions=[
xx([}], brace)
xx([{], brace)
xx(FORCE, cm, force_cm)
xx(TORQUE, cm, torque_cm)
xx(FORCE_OR_TORQUE, cm, force_or_torque_cm)
xx(DURATION, cm)
xx(TEMPERATURE, cm)
xx(SQUEEZE, cm)
xx(BEGIN)
xx(COBEGIN)
xx(END)
xx(COEND, end)
xx([;], end)
xx([(], open_paren)
xx(SCALAR, declare, scalar_value)
xx(VECTOR, declare, vector_value)
xx(ROT, declare, rot_value)
xx(FRAME, declare, frame_value)
xx(PLANE, declare, plane_value)
xx(TRANS, declare, trans_value)
xx(EVENT, declare, event_value)
xx(ATOM, declare, atom_value)
xx(WORLD, declare, world_value)
xx(CM_LABEL, declare, cm_label_value)
xx(CLC_LABEL, declare, clc_label_value)
xx(CH_LABEL, declare, ch_label_value)
xx(LABEL, declare, label_value)
xx(GLOBAL)
xx(IF)
xx(PLAN)
xx(WHILE)
xx(FOR)
xx(MOVE)
xx(AFFIX)
xx(UNFIX)
xx(SIGNAL)
xx(WAIT)
xx(WHEN)
xx(DUMP)
xx(ASSERT)
xx(DENY, assert)
xx(ON)
xx(REFERENCE)
xx(PARSESHIT)
xx(OPEN)
xx(CLOSE, open)
xx(CENTER)
xx(STOP)
xx(DEFINE)
xx(REQUIRE)
xx(DIMENSION)
xx(COMMENT, dimension)
xx(ABORT)
xx(PRINT, abort)
xx(PAUSE, abort)
xx([,], comma)
xx(OR, or, or_X)
xx(AND, and, and_X)
xx(NOT, not, not_X)
xx([∨], or, or_X)
xx([∧], and, and_X)
xx([¬], not, not_X)
xx([=], order, seq_X)
xx([≠], order, sne_X)
xx([>], order, sgt_X)
xx([<], order, slt_X)
xx([≥], order, sge_X)
xx([≤], order, sle_X)
xx([|], abs)
xx(VVVTRANS, abs)
xx([+], add, plus_X)
xx([-], add, minus_X)
xx([.], mult, vdot_X)
xx([*], mult, times_X)
xx([/], mult, sdiv_X)
xx([⊗], mult, vcross_X)
xx(WRT, mult, wrt_X)
xx(VVROT, mult, vvrot_X)
xx(→, trans, →_X)
xx([↑], trans, stos_X)
xx([#], vector, nomv_X)
xx(ORIENT, vector, orient_X)
xx(UNIT, vector, uvect_X)
xx(AXIS, vector, axis_X)
xx(POS, vector, pos_X)
xx(INV, vector, rinv_X)
xx([)], close_paren)
xx(VIA)
xx(WITH)
xx(SOURCE_FILE)
xx(DELIMITERS)
xx(UNSTACK_DELIMITERS)
xx(REPLACE_DELIMITERS)
xx(DISTANCE, metric, distance_METRIC)
xx(TIME, metric, time_METRIC)
xx(MASS, metric, mass_METRIC)
xx(ANGLE, metric, angle_METRIC)
xx(ARRIVAL)
xx(DEPARTURE, arrival)
xx(WOBBLE, wobble)
xx([?], misc)
xx(ABS, misc)
xx(TO, misc)
xx(TRACING, misc)
xx(WHERE, misc)
xx(THEN, misc)
xx(ENABLE, misc)
xx(DISABLE, misc)
xx(DO, misc)
xx(FORM, misc)
xx(AT, misc)
xx(BY, misc)
xx(CHANGING, misc)
xx(ALSO, misc)
xx(DONT, misc)
xx(ONLY, misc)
xx(RIGIDLY, misc)
xx(NONRIGIDLY, misc)
xx(STEP, misc)
xx(UNTIL, misc)
xx(ELSE, misc)
];
define
reserved_count=0;
redefine xx(name, class, special)=[
redefine reserved_count=reserved_count+1;];
reserved_definitions;
redefine xx(name, class, special)=["name",];
preload_array(
reserved_words, reserved_definitions, string, 1, reserved_count);
redefine xx(name, class, special)=[
ifc "class"=null
thenc redefine xxtemp=[name] & "_RES";
elsec redefine xxtemp=[class] & "_RES";
endc
xxtemp,];
preload_array(
reserved_class, reserved_definitions, integer, 1, reserved_count);
redefine xx(name, class, special)=[
ifc "special"=null thenc 0 elsec special endc,];
preload_array(
reserved_special, reserved_definitions, integer, 1, reserved_count);
string array
reserved[0:hasher-1];
integer array
com_type[0:hasher-1];
! init_reserved;
forward INTEGER PROCEDURE HASH(STRING S;INTEGER MAX);
procedure init_reserved;
α string s; integer i, k;
boolean procedure find_sym(string s; reference integer k);
α string probe;
k ← hash(s, hasher);
while (probe ← reserved[k])≠null do
if equ(s, probe) then return(true) else k ← (k+1) mod hasher;
return(false);
β;
arrclr(reserved); arrclr(com_type);
for i ← 1 step 1 until reserved_count do
if find_sym(reserved_words[i], k)
then outstr(reserved_words[i] & " doubly defined!" & crlf)
else
α
reserved[k] ← reserved_words[i];
com_type[k] ← reserved_class[i]+reserved_special[i]*hasher;
β;
β;
require init_reserved initialization [0];
! predefined constants;
define constant_definitions=[
XX(GARB_ID, scalar, nil) ! do not move this entry;
XX(PI, scalar, nil)
XX(CM, scalar, distance)
XX(SEC, scalar, time)
XX(GM, scalar, mass)
XX(DEG, scalar, angle)
XX(XHAT, vector, distance)
XX(YHAT, vector, distance)
XX(ZHAT, vector, distance)
XX(NILVECT, vector, distance)
XX(NILROTN, rot, angle)
XX(NILTRANS, trans, distance)
XX(STATION, trans, distance)
XX(YPARK, trans, distance)
XX(BPARK, trans, distance)
XX(BLUE, trans, distance)
XX(YELLOW, trans, distance)
XX(BHAND, scalar, distance)
XX(BARM, trans, distance)
XX(YHAND, scalar, distance)
XX(YARM, trans, distance)
XX(TRUE, boole, nil)
XX(FALSE, boole, nil)
];
define
const_count = 0;
redefine xx(str, i1, i2)=[redefine const_count = const_count+1;];
constant_definitions;
define zap_const(name, type, arg, postfix)=[
ifc "postfix"=null
thenc redefine xx(str, i1, i2)=[arg,];
elsec redefine xx(str, i1, i2)=[arg] & [postfix,];
endc
preload_array(name, constant_definitions, type, 1, const_count)];
zap_const(
preconst, string, "str");
zap_const(
preconst_type, integer, i1, _VALUE);
zap_const(
pre_dimens, integer, i2, _METRIC);
! compiler switches and control tables;
! As the AL compile time system runs, several intermediate files are created
and destroyed. The default extensions of these files are listed below.
.AL user the ALGOL like AL source language
.LOG user file of errors detected by the PARSER
.SEX AL s-expression version of AL source code
.ALP (.AL0) ALC pseudo code
.ALT (.AL1) ALC trajectory file
.ALV (.AL2) ALC constants and variable definitions for pseudo code
.ALS (.AL3) ALC symbol table usable by the PDP-11 runtime system
.ALL ALC hybrid s-expression/real AL listing
.LST PALX PDP-11 assembly code listing
.BIN PALX PDP-11 binary file loaded by 11TTY
.DMP 11TTY PDP-11 core image
;
! compiler switches;
define compiler_switches=[
xx(K, false) ! keep extraneous intermediate files: .ALP, .ALV, .ALT;
xx(S, false) ! inhibit the deletion of the .SEX file;
xx(L, false) ! generate a PALX assembly listing;
xx(B, false) ! run BAIL immediately after scanning the command line;
xx(E, false) ! load the .BIN file into the PDP-11;
];
indices(compiler_switches, _X);
define
switch_max =xxcount-1;
redefine xx(name, default)=["name",]; preload_array(
switch_name, compiler_switches, string, 0, switch_max+1);
redefine xx(name, default)=[default,]; preload_array(
switch_default, compiler_switches, boolean, 0, switch_max+1);
boolean array
switch_setting[0:switch_max];
procedure preset_switches;
α integer i;
for i ← 0 step 1 until switch_max do switch_setting[i] ← switch_default[i];
β;
require preset_switches initialization[0];
! hash, declaration of debugging variables, start of hidden_parse;
INTEGER PROCEDURE HASH(STRING S;INTEGER MAX);
α INTEGER I,TOT,C;
C←I←1; TOT←0;
WHILE I≠0 DO TOT←TOT+(C←C+1)*(I←LOP(S));
RETURN(TOT MOD MAX);
β;
ifc debug_compile thenc ! some variables that can be used for debugging;
require "BREAK.HDR[1,PJ]" source_file;
record_pointer(any_class)
__r0, __r1, __r2, __r3, __r4, __r5, __r6, __r7, __r8, __r9;
string
__s0, __s1, __s2, __s3, __s4, __s5, __s6, __s7, __s8, __s9;
integer
__i0, __i1, __i2, __i3, __i4, __i5, __i6, __i7, __i8, __i9;
real
__x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7, __x8, __x9;
procedure debug_init;
α
__r0 ← __r1 ← __r2 ← __r3 ← __r4 ← __r5 ← __r6 ← __r7 ← __r8 ← __r9 ← null_record;
__s0 ← __s1 ← __s2 ← __s3 ← __s4 ← __s5 ← __s6 ← __s7 ← __s8 ← __s9 ← null;
__i0 ← __i1 ← __i2 ← __i3 ← __i4 ← __i5 ← __i6 ← __i7 ← __i8 ← __i9 ← 0;
__x0 ← __x1 ← __x2 ← __x3 ← __x4 ← __x5 ← __x6 ← __x7 ← __x8 ← __x9 ← 0.0;
β;
require debug_init initialization[0];
endc
! The following (making all of parse a recursive procedure) is a hack to get the
restart option to work properly. As soon as a better way is found of
making sure everything gets reinitialized properly, this should be taken
out;
recursive procedure hidden_parse;
α "hidden_parse"
! ---- DECLARATIONS ----;
external integer
rpgsw;
record_pointer(file)
AL_file, ! AL source file;
SEX_file, ! s-expression file;
BIN_file, ! PALX binary file;
ALL_file, ! ALC listing file;
LOG_file; ! LOG listing file;
BOOLEAN
DISK, ! TRUE IF INPUT IS COMING FROM DISK;
AUTO_PROCEED, ! TRUE IF AUTO_PROCEED SWITCH IS ON FOR ERROR RECOVERY;
LOGGING; ! TURE IF LOGGING WANTED;
STRING
cmd_line,
INFILE,
OUTFILE, ! INPUT,OUTPUT & LOG FILES;
LOGFILE;
INTEGER
CHANIN,
CHANOUT,
CHANLOG;
STRING
INSTRING, ! INPUT STRING;
TABLE1; ! BREAK TABLES;
INTEGER
TYPE_OF_TOKEN;
define
special_token =0,
id_token =1,
numeric_token =2,
string_token =3;
integer
TYPE_OF_RES_WORD, ! TYPE PULLED OFF OF COM_TYPE;
SPECIAL_INFO, ! INFO PASSED FROM SCANNER TO PARSER - DEPENDS ON TYPE;
word_R_break, ! break tables;
non_blank_break,
word_S_break,
close_brace_break,
non_digit_break,
quote_break,
macro_delimiter_break,
semicolon_A_break,
cr_break,
paren_cr_break,
lf_ff_break,
semicolon_R_break,
omit_break;
STRING
TOKEN,
CURRENT_FRAME; ! TOKEN OF THE CURRENT FRAME - DEFAULT SET TO "YARM";
INTEGER
SPACING; ! SPACING FOR OUTPUT;
BOOLEAN
REJECT; ! TRUE WHEN THE LAST TOKEN IS REJECTED BY THE CALLING PROC;
INTEGER
DEC_NUM; ! THE NUMBER OF DECLARATIONS IN THE CURRENT BLOCK;
STRING
OUTEXPR; ! FOR THE CONSTRUCTION OF THE STRING FOR EXPRESSIONS;
RECORD_CLASS
PARAM_LIST(
STRING
ID;
RECORD_POINTER(PARAM_LIST)
NEXT
);
RECORD_CLASS
MACRO_LIST(
STRING
VALUE, ! ACTUAL MACRO body;
ID;
INTEGER
NUM; ! NUMBER OF PARAMETERS;
RECORD_POINTER(MACRO_LIST)
NEXT, ! POINTS TO NEXT MACRO WHICH HASHES TO THE SAME ENTRY;
LAST, ! BACK POINTER IN THE SAME LIST;
LINK; ! USED ONLY FOR PARAMETER EXPANSION, POINTS TO THE
PARAMETER DEFINED JUST BEFORE THIS ONE;
RECORD_POINTER(PARAM_LIST)
PARAMS
);
RECORD_POINTER(MACRO_LIST)
TOP_PARAM;
RECORD_POINTER(MACRO_LIST) ARRAY
MACRO_TABLE[0:hasher];
RECORD_CLASS
DELIMITER_LIST(
STRING
D1,
D2;
RECORD_POINTER(DELIMITER_LIST)
NEXT
);
RECORD_POINTER(DELIMITER_LIST)
TOP_DELIMITERS;
RECORD_CLASS
SOURCE_LIST(
INTEGER
CHAN, ! i/o CHANNEL NUMBER OF input, -1 if from macro;
NUM; ! NUMBER OF PARAMETERS IN THE CURRENT MACRO;
STRING
CUR_STRING, ! curline WHEN PUSHED;
CUR_STRINGR, ! curliner WHEN PUSHED;
FILE_NAME; ! NAME OF THE INPUT FILE WHEN PUSHED;
RECORD_POINTER(SOURCE_LIST)
NEXT;
INTEGER
PN,
LN ! PAGE AND LINE NUMBER OF THE PUSHED FILE;
);
RECORD_POINTER(SOURCE_LIST)
TOP_SOURCE;
RECORD_CLASS
DIMENS_LIST(
INTEGER
VALUE;
RECORD_POINTER(DIMENS_LIST)
NEXT
);
RECORD_POINTER(DIMENS_LIST)
UPPER_D,
LOWER_D;
RECORD_CLASS
ID_LIST(
STRING
NAME;
INTEGER
TYPE;
RECORD_POINTER(ID_LIST)
NEXT, ! POINTS TO NEXT ID WHICH HASHES TO THE SAME ENTRY;
LINK; ! POINTS TO THE ID DEFINED JUST BEFORE THIS ONE;
BOOLEAN
LABEL_USED;
INTEGER
DIMEN_P,
BLOCK_LEVEL_OF_DEFN
);
RECORD_POINTER(ID_LIST) ARRAY
SYMBOL_TABLE[0:hasher];
RECORD_POINTER(ID_LIST)
TOP_ID;
RECORD_POINTER(DIMENS_LIST)
DISTANCE_DIMENS, ! WILL HOLD DIMENS LIST FOR DISTANCE -- NEEDED FOR ⊗;
ANGLE_DIMENS; ! WILL HOLD DIMENS LIST FOR ANGLES -- NEEDED FOR ROT;
INTEGER
EXP_TYPE; ! TYPE OF EXPRESSION FOUND BY P_EXP;
BOOLEAN
PLAN_STATEMENT; ! TRUE IF CURRENT STATMENT IS PREFIXED BY PLAN;
STRING
CHANGER_HEAD; ! NON NULL IF PARSING A STATEMENT INSDIDE A CHANGER;
INTEGER
T_COUNT; ! COUNTER FOR PRODUCING UNIQUE ID'S;
RECORD_POINTER(DIMENS_LIST)
EXP_UP_D,
EXP_LOW_D;
RECORD_CLASS
EXPR(
INTEGER
TYPE;
STRING
OP,
ID;
RECORD_POINTER(DIMENS_LIST)
UPPER_DIMEN,
LOWER_DIMEN;
RECORD_POINTER(ANY_CLASS)
PARTS
);
RECORD_CLASS
EXPR_LIST(
RECORD_POINTER(EXPR)
EXP;
RECORD_POINTER(EXPR_LIST)
NEXT
);
RECORD_CLASS
OP_LIST(
RECORD_POINTER(OP_LIST)
NEXT;
INTEGER
PRIORITY,
OP,
NUM_OF_ARGS,
COUNT;
BOOLEAN
ARG_DEP,
FUNC
);
BOOLEAN
OP_EXPECTED; ! TRUE WHEN P_EXP EXPECTS AN OPERATION;
RECORD_POINTER(OP_LIST)
OPS,
OPSAVE;
RECORD_POINTER(EXPR_LIST)
EXPRS,
EXPRSAVE;
RECORD_POINTER(EXPR)
EXP1,
EXP2,
EXP3;
INTEGER
DELIMITER_1, ! non-zero only while defining macro;
DELIMITER_2; ! HEAD AND TAIL DELIMITER OF macro bodies;
INTEGER
MAC_NUM; ! NUMBER OF PARAMS IN THE CURRENT MACRO EXPANSION;
RECORD_POINTER(DIMENS_LIST) ARRAY
DIMEN_DEFS,
DIMEN_DEFS2[0:16];
INTEGER
DIMEN_NUM,
BLOCK_LEVEL;
! GARBAGE DECLARATIONS (VERY LOCAL);
BOOLEAN
T,
EOF;
INTEGER
COUNT,
I,
N,
BRCHAR;
STRING
GARB;
INTEGER
LINENUM,
PAGENUM,
SOSNUM,
typed_page_num, ! on tty;
sourcelvl;
STRING
CURLINER,
CURLINE;
! error, error_reject, print, file_indent;
FORWARD RECURSIVE PROCEDURE P_STATEMENT;
FORWARD RECURSIVE PROCEDURE GET_TOKEN;
string procedure source_pos;
return("File "& INFILE& ", Page "& CVS(PAGENUM+1)& ", Line "& CVS(LINENUM));
forward boolean procedure got_output(record_pointer(file) F);
PROCEDURE ERROR(INTEGER I;STRING S);
! RIGHT NOW THIS PROCEDURE IS KIND OF DUMB. IT'S INCLUDED IN THE HOPE
OF EVENTUALLY MAKING THE ERROR FACILITY MORE VERSATILE;
! I don't understand the error number stuff. All errors numbered 200
have been added by me and can be arbitrarily reassigned.
PJ 8/30/76;
α INTEGER L1,L2; BOOLEAN PROCEED,LOGGING; INTEGER COMMAND_CHAR;
WHILE EQU(CURLINE[1 TO 1], lf) DO GARB←LOP(CURLINE);
L1←LENGTH(CURLINER); L2←LENGTH(CURLINE)-L1; PROCEED←AUTO_PROCEED;
OUTSTR(crlf & "YOU LOOSE - ERROR TYPE " & CVS(I) & crlf & S & crlf
& source_pos & crlf & CURLINE[1 TO L2] & lf & CURLINER & crlf);
IF LOGGING THEN
OUT(CHANLOG,crlf & "YOU LOOSE - ERROR TYPE " & CVS(I) & crlf & S & crlf
& source_pos & crlf & CURLINE[1 TO L2] & lf & CURLINER & crlf);
WHILE ¬PROCEED DO
α
CLRBUF; OUTSTR("↑"); COMMAND_CHAR←INCHRW;
IF COMMAND_CHAR="B" THEN
α
OUTSTR("ail" & crlf);
IFC debug_compile
THENC BAIL
ELSEC OUTSTR("Sorry, Bail not loaded." & crlf)
ENDC;
β
ELSE IF COMMAND_CHAR=cr THEN
α CLRBUF; PROCEED←TRUE; β
ELSE IF COMMAND_CHAR=lf THEN
α PROCEED←TRUE; AUTO_PROCEED←TRUE; β
ELSE IF COMMAND_CHAR="E" THEN
α OUTSTR("dit" & crlf);
CLOSO(CHANLOG);
EDFILE(INFILE,LINENUM,PAGENUM+1,0);
β
ELSE IF COMMAND_CHAR="R" THEN
α
OUTSTR("estart"); CURLINE←CURLINER←null;
USERERR(0,1,NULL,"S"); ! THIS IS A HACK AND SHOULD BE CHANGED
AS SOON AS POSSIBLE;
β
ELSE IF COMMAND_CHAR="X" THEN
α OUTSTR("it" & crlf);
USERERR(0,1,NULL,"X"); ! DITTO ABOVE COMMENT;
β
ELSE IF (COMMAND_CHAR="L" AND LOGGING≠TRUE) THEN
α
LOG_file←new_record(file);
copy_file_record(LOG_file,BIN_file);
file:mode[LOG_file]←0; file:in_bfrs[LOG_file]← 0;
file:out_bfrs[LOG_file]←12; file:ext[LOG_file] ← "LOG";
file:device[LOG_file]← "DSK";
file:name[LOG_file]←file:name[AL_file];
if ¬got_output(LOG_file) then
usererr(0, 1, "can't get output");
CHANLOG ← file:chn[LOG_file];
LOGFILE←make_file_name(LOG_file);
OUT(CHANLOG,crlf & "YOU LOOSE - ERROR TYPE " & CVS(I) & crlf & S & crlf
& source_pos & crlf & CURLINE[1 TO L2] & lf & CURLINER & crlf);
OUTSTR("ogging in file name " & LOGFILE & crlf );
LOGGING←TRUE;
β
ELSE α
OUTSTR("Reply [CR] to continue," & crlf &
"[LF] to continue automatically," & crlf &
"""B"" to load Bail," & crlf &
"""E"" to edit source file," & crlf &
"""R"" to restart," & crlf &
"""X"" to exit");
IF ¬LOGGING THEN OUTSTR("," & crlf & """L"" for logging");
OUTSTR("." & crlf);
β;
β;
β;
PROCEDURE ERROR_REJECT(INTEGER I;STRING S);
α ERROR(I,S); REJECT←TRUE; β;
PROCEDURE PRINT(STRING S);
α
ifc debug_compile thenc
INTEGER I,J,K,L;
FOR I←1 STEP 1 UNTIL SPACING DO S←" "&S;
J←LENGTH(S);
WHILE J>80 DO
α;
K←80;
WHILE K≤J AND ¬EQU(S[K TO K]," ") DO K←K+1;
OUT(CHANOUT,S[1 TO K] & crlf);
S←S[K+1 TO J];
J←J-K;
β;
OUT(CHANOUT,S & crlf)
elsec
INTEGER I;
FOR I←1 STEP 1 UNTIL SPACING DO OUT(CHANOUT," ");
OUT(CHANOUT,S & crlf);
endc;
β;
procedure file_indent(integer i);
α
typed_page_num ← false;
outstr(" "[1 for 2*i]);
β;
! read, push_macro_delimiters;
STRING PROCEDURE READ(INTEGER BTABLE);
! RIGHT NOW THIS PROCEDURE IS KIND OF DUMB. IT'S INCLUDED IN THE HOPE
OF EVENTUALLY MAKING THE READING FACILITY MORE VERSATILE;
α STRING TEXT;
text ← SCAN(CURLINER,BTABLE,BRCHAR);
WHILE BRCHAR=0 DO
α BOOLEAN REPLACED;
REPLACED←TRUE;
IF CHANIN≠-1 THEN CURLINE←CURLINER←INPUT(CHANIN,lf_ff_break);
IF CHANIN=-1 THEN
α "pop macro"
FOR I←1 STEP 1 UNTIL SOURCE_LIST:NUM[TOP_SOURCE] DO
α
IF REPLACED AND EQU(TEXT,MACRO_LIST:ID[TOP_PARAM]) THEN
α
TEXT←MACRO_LIST:VALUE[TOP_PARAM];
REPLACED←FALSE;
SOURCE_LIST:CUR_STRINGR[TOP_SOURCE]←" "&
SOURCE_LIST:CUR_STRINGR[TOP_SOURCE];
β;
IF MACRO_LIST:LAST[TOP_PARAM]=NULL THEN
MACRO_TABLE[HASH(MACRO_LIST:ID[TOP_PARAM],hasher)]
← MACRO_LIST:NEXT[TOP_PARAM]
ELSE IF MACRO_LIST:NEXT[TOP_PARAM]=NULL THEN
MACRO_LIST:LAST[TOP_PARAM]
← MACRO_LIST:NEXT[TOP_PARAM]
ELSE α
MACRO_LIST:LAST[TOP_PARAM]
← MACRO_LIST:NEXT[TOP_PARAM];
MACRO_LIST:NEXT[TOP_PARAM]
← MACRO_LIST:LAST[TOP_PARAM];
β;
β;
CHANIN←SOURCE_LIST:CHAN[TOP_SOURCE];
CURLINE←SOURCE_LIST:CUR_STRING[TOP_SOURCE];
CURLINER←" "&SOURCE_LIST:CUR_STRINGR[TOP_SOURCE];
PAGENUM←SOURCE_LIST:PN[TOP_SOURCE];
LINENUM←SOURCE_LIST:LN[TOP_SOURCE];
TOP_SOURCE←SOURCE_LIST:NEXT[TOP_SOURCE];
β "pop macro"
ELSE IF BRCHAR=lf THEN LINENUM←LINENUM+1
ELSE IF BRCHAR=ff THEN
α
outstr(" " & cvs((PAGENUM←PAGENUM+1)+1));
typed_page_num ← true; LINENUM←0
β
ELSE IF TOP_SOURCE≠NULL THEN
α "close_source"
RELEASE(CHANIN);
PAGENUM←SOURCE_LIST:PN[TOP_SOURCE];
LINENUM←SOURCE_LIST:LN[TOP_SOURCE];
CURLINE←SOURCE_LIST:CUR_STRING[TOP_SOURCE];
CURLINER←SOURCE_LIST:CUR_STRINGR[TOP_SOURCE];
CHANIN←SOURCE_LIST:CHAN[TOP_SOURCE];
INFILE←SOURCE_LIST:FILE_NAME[TOP_SOURCE];
MAC_NUM←SOURCE_LIST:NUM[TOP_SOURCE];
TOP_SOURCE←SOURCE_LIST:NEXT[TOP_SOURCE];
outstr(crlf); typed_page_num ← false; sourcelvl ← sourcelvl-1;
β "close_source"
ELSE IF EOF THEN ERROR(500,"end of file encountered unexpectedly.");
TEXT ← TEXT & SCAN(CURLINER,BTABLE,BRCHAR);
β;
RETURN(TEXT);
β;
procedure push_delimiters(string s);
α record_pointer(delimiter_list) new_del;
DELIMITER_LIST:NEXT[NEW_DEL ← new_record(delimiter_list)] ← TOP_DELIMITERS;
DELIMITER_LIST:D1[NEW_DEL] ← lop(s); DELIMITER_LIST:D2[NEW_DEL] ← lop(s);
TOP_DELIMITERS←NEW_DEL;
β;
! mac_test_and_expand;
! TEST TO SEE IF A GIVEN TOKEN IN THE NAME OF A MACRO AND IF IT IS, EXPAND IT;
RECURSIVE PROCEDURE MAC_TEST_AND_EXPAND;
α INTEGER HASH_ENTRY; RECORD_POINTER (MACRO_LIST) MAC_POINT2;
HASH_ENTRY←HASH(TOKEN,hasher); MAC_POINT2←MACRO_TABLE[HASH_ENTRY];
WHILE MAC_POINT2≠NULL AND ¬EQU(MACRO_LIST:ID[MAC_POINT2],TOKEN) DO
MAC_POINT2←MACRO_LIST:NEXT[MAC_POINT2];
IF MAC_POINT2=NULL
THEN TYPE_OF_TOKEN←id_token
ELSE
α "expand macro"
STRING MAC_ID; RECORD_POINTER(PARAM_LIST) PARAMS;
RECORD_POINTER(SOURCE_LIST)NEW_SOURCE2;
PARAMS←MACRO_LIST:PARAMS[MAC_POINT2]; MAC_ID←TOKEN; GET_TOKEN;
IF ¬EQU(TOKEN,"(") AND PARAMS≠NULL
THEN ERROR(59,"Parametered macro used without params.")
ELSE IF ¬EQU(TOKEN,"(")
THEN CURLINER←TOKEN&CURLINER
ELSE
α "macro parameters" STRING VALUE, NAME;
FOR I←1 STEP 1 UNTIL MACRO_LIST:NUM[MAC_POINT2] DO
α RECORD_POINTER(MACRO_LIST)SUB_MACRO;
NAME←PARAM_LIST:ID[PARAMS]; PARAMS←PARAM_LIST:NEXT[PARAMS];
IF EQU(TOKEN,")") THEN
ERROR(60,"Number of parameters disagree with definition.");
GET_TOKEN;
IF TYPE_OF_TOKEN≠string_token THEN
ERROR(61,"Need a string here.");
VALUE←TOKEN;
GET_TOKEN;
IF ¬EQU(TOKEN,",") AND ¬EQU(TOKEN,")") THEN
ERROR_REJECT(62,"Need either comma or right paren here.");
SUB_MACRO←NEW_RECORD(MACRO_LIST);
MACRO_LIST:VALUE[SUB_MACRO]←VALUE;
MACRO_LIST:ID[SUB_MACRO]←NAME;
MACRO_LIST:NUM[SUB_MACRO]←0;
MACRO_LIST:LINK[SUB_MACRO]←TOP_PARAM;
TOP_PARAM←SUB_MACRO;
HASH_ENTRY←HASH(NAME,hasher);
MACRO_LIST:NEXT[SUB_MACRO]←MACRO_TABLE[HASH_ENTRY];
IF MACRO_TABLE[HASH_ENTRY]≠NULL
THEN MACRO_LIST:LAST[MACRO_TABLE[HASH_ENTRY]] ← MAC_POINT2;
MACRO_TABLE[HASH_ENTRY]←SUB_MACRO;
β;
IF ¬EQU(TOKEN,")") THEN ERROR(62,"Number of parameters don't match the defn.");
β "macro parameters";
NEW_SOURCE2←NEW_RECORD(SOURCE_LIST);
SOURCE_LIST:CHAN[NEW_SOURCE2]←CHANIN;
SOURCE_LIST:NUM[NEW_SOURCE2]←MACRO_LIST:NUM[MAC_POINT2];
SOURCE_LIST:NEXT[NEW_SOURCE2]←TOP_SOURCE;
SOURCE_LIST:CUR_STRING[NEW_SOURCE2]←CURLINE;
SOURCE_LIST:CUR_STRINGR[NEW_SOURCE2]←CURLINER;
SOURCE_LIST:PN[NEW_SOURCE2]←PAGENUM;
SOURCE_LIST:LN[NEW_SOURCE2]←LINENUM;
CHANIN←-1;
CURLINE←CURLINER←MACRO_LIST:VALUE[MAC_POINT2];
TOP_SOURCE←NEW_SOURCE2;
GET_TOKEN;
β "expand macro";
β;
! get_token;
! THIS PROCEDURE GETS THE NEXT TOKEN. PUTS THE TOKEN IN "TOKEN" THE TYPE OF
THE TOKEN IN "TYPE_OF_TOKEN";
RECURSIVE PROCEDURE GET_TOKEN;
α "get_token" BOOLEAN T; INTEGER POINT;
IF REJECT THEN α REJECT←FALSE; RETURN; β;
TYPE_OF_TOKEN←special_token; T←TRUE;
WHILE T DO
α "while_T"
READ(non_blank_break); TOKEN←READ(word_R_break);
IF EQU(TOKEN,NULL) THEN
α "isolated break"
IF BRCHAR="."
THEN
α REAL NUM;
CURLINER←"0"&CURLINER;
if (NUM←REALSCAN(CURLINER,BRCHAR))≠0
THEN
α
TYPE_OF_TOKEN←numeric_token; TOKEN←CVG(NUM)
β
ELSE TOKEN←".";
β
ELSE IF BRCHAR="-" THEN
α REAL NUM;
garb ← LOP(CURLINER); CURLINER←"-0"&CURLINER;
if (NUM←REALSCAN(CURLINER,BRCHAR))≠0
THEN
α
TYPE_OF_TOKEN←numeric_token; TOKEN←CVG(NUM)
β
ELSE TOKEN←"-";
β;
IF EQU(TOKEN,NULL) THEN α READ(word_S_break); TOKEN←BRCHAR; β;
β "isolated break";
IF EQU(TOKEN,"{") THEN TOKEN←READ(close_brace_break) ELSE T←FALSE;
β "while_T";
IF TOKEN=dquote THEN
α "found_string"
TOKEN←READ(quote_break); TYPE_OF_TOKEN←string_token;
while curliner=dquote do token ← token & lop(curliner) & read(quote_break);
RETURN;
β "found_string";
! delimiter_1 non-zero only while defining macro;
if delimiter_1 and token=delimiter_1 then
α "found_macro_body" integer lvl;
token←read(macro_delimiter_break); type_of_token ← string_token;
if delimiter_1=delimiter_2 ∨ brchar=delimiter_2 then return;
lvl ← 2; if brchar≠delimiter_1 then error(200, "macro body scan lost");
do α
token ← token & brchar & read(macro_delimiter_break);
if brchar=delimiter_2
then lvl ← lvl-1
else if brchar=delimiter_1
then lvl ← lvl+1
else error(200, "macro body scan lost");
β
until lvl ≤ 0;
return;
β "found_macro_body";
! look for reserved word;
IF TYPE_OF_TOKEN=special_token THEN
α
POINT←HASH(TOKEN,hasher);
WHILE ¬EQU(RESERVED[POINT],NULL) AND ¬EQU(RESERVED[POINT],TOKEN) DO
POINT←(POINT+1)MOD hasher;
IF RESERVED[POINT]=TOKEN
THEN
α "reserved word" INTEGER VAL;
TYPE_OF_TOKEN←special_token;
VAL←COM_TYPE[POINT];
IF VAL≥hasher
THEN
α
SPECIAL_INFO←(VAL DIV hasher);
TYPE_OF_RES_WORD←(VAL MOD hasher);
β
ELSE α SPECIAL_INFO←0; TYPE_OF_RES_WORD←VAL; β;
β "reserved word"
ELSE
α "not reserved"
IF ¬("0" ≤ token ≤ "9")
THEN MAC_TEST_AND_EXPAND
ELSE
α "numeric" REAL NUM1,NUM2; INTEGER NUMGARB;
TYPE_OF_TOKEN←numeric_token;
NUM1←INTSCAN(TOKEN,NUMGARB);
IF ¬EQU(TOKEN,NULL) THEN ERROR(0,"Illegal token." &
crlf & "Garbage after digits will be ignored.");
IF BRCHAR="."
THEN
α
CURLINER←"0"&CURLINER;
NUM2←REALSCAN(CURLINER,BRCHAR);
TOKEN←CVG(NUM1+NUM2);
β
ELSE IF BRCHAR="@"
THEN
α
CURLINER←"1"&CURLINER;
NUM2←REALSCAN(CURLINER,BRCHAR);
TOKEN←CVG(NUM1*NUM2);
β
ELSE TOKEN←CVG(NUM1);
β "numeric";
β "not reserved";
β;
β "get_token";
! check;
PROCEDURE CHECK(STRING S; REFERENCE RECORD_POINTER(DIMENS_LIST) D1,D2,D3,D4);
α RECORD_POINTER(DIMENS_LIST) II1,II2,II3,II4;
II1←D1; II2←D2; II3←D3; II4←D4;
WHILE II1≠NULL_RECORD AND II3≠NULL_RECORD DO
α
IF DIMENS_LIST:VALUE[II1]≠DIMENS_LIST:VALUE[II3] THEN
ERROR(122,"Dimensions don't match on "&S&".");
II1←DIMENS_LIST:NEXT[II1]; II3←DIMENS_LIST:NEXT[II3];
β;
IF II1≠NULL_RECORD OR II3≠NULL_RECORD THEN
ERROR(122,"Dimensions don't match on "&S&".");
WHILE II2≠NULL_RECORD AND II4≠NULL_RECORD DO
α
IF DIMENS_LIST:VALUE[II2]≠DIMENS_LIST:VALUE[II4] THEN
ERROR(122,"Dimensions don't match on "&S&".");
II2←DIMENS_LIST:NEXT[II2]; II4←DIMENS_LIST:NEXT[II4];
β;
IF II2≠NULL_RECORD OR II4≠NULL_RECORD THEN
ERROR(122,"Dimensions don't match on "&S&".");
β;
! combine
calling sequence:
combine(expr:UPPER_DIMEN[cur_expr], expr:LOWER_DIMEN[cur_expr],
expr:UPPER_DIMEN[e1], expr:LOWER_DIMEN[e1],
expr:UPPER_DIMEN[e2], expr:LOWER_DIMEN[e2])
;
PROCEDURE COMBINE(REFERENCE RECORD_POINTER(DIMENS_LIST) D1, D2, D3, D4, D5, D6);
α RECORD_POINTER(DIMENS_LIST) I1, I2, I3, I4, I5, I6;
I1 ← D1 ← NEW_RECORD(DIMENS_LIST); I2 ← D2 ← NEW_RECORD(DIMENS_LIST);
I3 ← D3; I4 ← D4; I5 ← D5; I6 ← D6;
WHILE I3≠NULL_RECORD OR I4≠NULL_RECORD OR I5≠NULL_RECORD OR I6≠NULL_RECORD DO
α RECORD_POINTER(DIMENS_LIST)T_D;
IF I3≠NULL_RECORD AND I6≠NULL_RECORD
AND DIMENS_LIST:VALUE[I3]=DIMENS_LIST:VALUE[I6]
THEN α I3 ← DIMENS_LIST:NEXT[I3]; I6 ← DIMENS_LIST:NEXT[I6] β
ELSE IF I4≠NULL_RECORD AND I5≠NULL_RECORD
AND DIMENS_LIST:VALUE[I4]=DIMENS_LIST:VALUE[I5]
THEN α I4 ← DIMENS_LIST:NEXT[I4]; I5 ← DIMENS_LIST:NEXT[I5] β
ELSE α INTEGER I_D; RECORD_POINTER(DIMENS_LIST)UPPER,LOWER;
BOOLEAN IS3, IS4, ISU;
INTEGER V3, V4, V5, V6, MIN_V;
! ?????; IF I3≠NULL_RECORD THEN V3 ← DIMENS_LIST:VALUE[I3] ELSE V3 ← 100;
IF I4≠NULL_RECORD THEN V4 ← DIMENS_LIST:VALUE[I4] ELSE V4 ← 100;
IF I5≠NULL_RECORD THEN V5 ← DIMENS_LIST:VALUE[I5] ELSE V5 ← 100;
IF I6≠NULL_RECORD THEN V6 ← DIMENS_LIST:VALUE[I6] ELSE V6 ← 100;
MIN_V ← V3 min V4 min V5 min V6; T_D ← NEW_RECORD(DIMENS_LIST);
DIMENS_LIST:VALUE[T_D] ← MIN_V;
IF V3=MIN_V THEN
α
DIMENS_LIST:NEXT[I1] ← T_D;
I3 ← DIMENS_LIST:NEXT[I3];
I1 ← T_D;
β
ELSE IF V5=MIN_V THEN
α
DIMENS_LIST:NEXT[I1] ← T_D;
I5 ← DIMENS_LIST:NEXT[I5];
I1 ← T_D;
β
ELSE IF V4=MIN_V THEN
α
DIMENS_LIST:NEXT[I2] ← T_D;
I4 ← DIMENS_LIST:NEXT[I4];
I2 ← T_D;
β
ELSE IF V6=MIN_V THEN
α
DIMENS_LIST:NEXT[I2] ← T_D;
I6 ← DIMENS_LIST:NEXT[I6];
I2 ← T_D;
β;
β;
β;
D1 ← DIMENS_LIST:NEXT[D1];
D2 ← DIMENS_LIST:NEXT[D2];
β;
! reduce, tmake_R;
PROCEDURE REDUCE;
α INTEGER CUR_OP_NUM; LABEL RAISE;
PROCEDURE FAIL_UP(INTEGER I; STRING S);
α RECORD_POINTER(EXPR)E;RECORD_POINTER(EXPR_LIST)EL;
ERROR(I,S&crlf&"I will reduce it to GARB_ID as default.");
E←NEW_RECORD(EXPR);
EL←NEW_RECORD(EXPR_LIST);
EXPR:TYPE[E]←scalar_VALUE;
EXPR:OP[E]←null;
EXPR:ID[E]←"GARB_ID";
EXPR_LIST:NEXT[EL]←EXPRS;
EXPR_LIST:EXP[EL]←E;
EXPRS←EL;
GO TO RAISE;
β;
procedure tmake_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! TMAKE FOUND;
RECORD_POINTER (EXPR) E1,E2,E3;
IF EXPRS=NULL_RECORD OR EXPR_LIST:NEXT[EXPRS]=NULL_RECORD THEN
FAIL_UP(108,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≠vector_VALUE THEN
α
E3←E1;
E1←E2;
E2←E3;
β;
IF EXPR:TYPE[E1]≠vector_VALUE OR EXPR:TYPE[E2]≠rot_VALUE THEN ERROR(109,"Type mismatch.");
TEMP←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[TEMP]←E1;
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[CUR_PARTS]←E2;
E3←NEW_RECORD(EXPR);
EXPR:PARTS[E3]←CUR_PARTS;
EXPR:OP[E3]←"TMAKE";
EXPR:TYPE[E3]←trans_VALUE;
EXPR_LIST:EXP[EXPRS]←E3;
β;
! vmake_R, fmake_R;
procedure vmake_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! VMAKE FOUND;
RECORD_POINTER (EXPR) CUR_EXPR;
INTEGER I;
FOR I←1 STEP 1 UNTIL 3 DO
α
IF EXPRS=NULL_RECORD THEN FAIL_UP(107,"Can't reduce expression.");
TEMP←EXPRS;
EXPRS←EXPR_LIST:NEXT[EXPRS];
EXPR_LIST:NEXT[TEMP]←CUR_PARTS;
CUR_PARTS←TEMP;
IF scalar_VALUE≠EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]]
THEN ERROR(108,"Type mismatch");
β;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:OP[CUR_EXPR]←"VMAKE";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
TEMP←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[TEMP]←CUR_EXPR;
EXPR_LIST:NEXT[TEMP]←EXPRS;
EXPRS←TEMP;
β;
procedure fmake_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! FMAKE FOUND;
RECORD_POINTER (EXPR) E1,E2,E3;
RECORD_POINTER (DIMENS_LIST) U_D,L_D;
IF EXPRS=NULL_RECORD OR EXPR_LIST:NEXT[EXPRS]=NULL_RECORD THEN
FAIL_UP(108,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≠vector_VALUE THEN
α E3←E1; E1←E2; E2←E3; β;
IF EXPR:TYPE[E1]≠vector_VALUE OR EXPR:TYPE[E2]≠rot_VALUE
THEN ERROR(109,"Type mismatch.");
! IF EXPR:UPPER_DIMEN[E1]≠DISTANCE_DIMENS THEN ERROR(1111,
"Dimensions don't match in vector part of frame");
! IF EXPR:UPPER_DIMEN[E2]≠ANGLE_DIMENS THEN ERROR(1111,
"Dimensions don't match in rot part of frame.");
TEMP←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[TEMP]←E1;
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[CUR_PARTS]←E2;
E3←NEW_RECORD(EXPR);
EXPR:PARTS[E3]←CUR_PARTS;
EXPR:OP[E3]←"FMAKE";
EXPR:TYPE[E3]←trans_VALUE;
EXPR:UPPER_DIMEN[E3]←distance_dimens;
EXPR_LIST:EXP[EXPRS]←E3;
β;
! vvtrans_R, sneg_R;
procedure vvtrans_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! VVVTRANS FOUND;
RECORD_POINTER (EXPR) CUR_EXPR;
INTEGER I;
FOR I←1 STEP 1 UNTIL 3 DO
α
IF EXPRS=NULL_RECORD THEN FAIL_UP(107,"Can't reduce expression.");
TEMP←EXPRS;
EXPRS←EXPR_LIST:NEXT[EXPRS];
EXPR_LIST:NEXT[TEMP]←CUR_PARTS;
CUR_PARTS←TEMP;
IF vector_VALUE≠EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]]
THEN ERROR(108,"Type mismatch");
β;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:OP[CUR_EXPR]←"VVVTRANS";
EXPR:TYPE[CUR_EXPR]←rot_VALUE;
TEMP←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[TEMP]←CUR_EXPR;
EXPR_LIST:NEXT[TEMP]←EXPRS;
EXPRS←TEMP;
β;
procedure sneg_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "SNEG" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≠scalar_VALUE THEN ERROR(112,"You can only take the opposite of scalars."
&crlf&"Continue will pass the bug through.");
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:OP[CUR_EXPR]←"SNEG";
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[CUR_PARTS]←E1;
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[E1];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[E1];
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
! rinv_R, sabs_R;
procedure rinv_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "RINV" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
CUR_EXPR←NEW_RECORD(EXPR);
IF EXPR:TYPE[E1]=rot_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"RINV";
EXPR:TYPE[CUR_EXPR]←rot_VALUE;
β
ELSE IF EXPR:TYPE[E1]=trans_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"TINVRT";
EXPR:TYPE[CUR_EXPR]←trans_VALUE;
β
ELSE ERROR(112,"You can only take the inverse of rotations and transforms."
&crlf&"Continue will pass bug through.");
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[CUR_PARTS]←E1;
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[E1];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[E1];
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
procedure sabs_R;
α ! "SABS" SHOULD BE HANDLED IN P_EXP; ERROR(-1,"PARSER ERROR"); β;
! plus_R;
procedure plus_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "+" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≥EXPR:TYPE[E2] THEN α E3←E1; E1←E2; E2←E3; β;
TEMP←NEW_RECORD(EXPR_LIST);
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[TEMP]←E1;
EXPR_LIST:EXP[CUR_PARTS]←E2;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
CHECK("addition expression",EXPR:UPPER_DIMEN[E1],EXPR:LOWER_DIMEN[E1],
EXPR:UPPER_DIMEN[E2],EXPR:LOWER_DIMEN[E2]);
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[E1];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[E1];
IF EXPR:TYPE[E1]=scalar_VALUE THEN
α
IF EXPR:TYPE[E2]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
EXPR:OP[CUR_EXPR]←"SADD";
EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
β
ELSE IF EXPR:TYPE[E1]=vector_VALUE THEN
α
IF EXPR:TYPE[E2]=vector_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"VADD";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
β
ELSE IF EXPR:TYPE[E2]=trans_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"TVADD";
EXPR:TYPE[CUR_EXPR]←trans_VALUE;
β
β
ELSE ERROR(109,"Type mismatch");
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
! minus_R;
procedure minus_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "-" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]>EXPR:TYPE[E2] THEN α E3←E1; E1←E2; E2←E3; β;
TEMP←NEW_RECORD(EXPR_LIST);
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[TEMP]←E1;
EXPR_LIST:EXP[CUR_PARTS]←E2;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
CHECK("subtraction expression",EXPR:UPPER_DIMEN[E1],EXPR:LOWER_DIMEN[E1],
EXPR:UPPER_DIMEN[E2],EXPR:LOWER_DIMEN[E2]);
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[E1];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[E1];
IF EXPR:TYPE[E1]=scalar_VALUE THEN
α
IF EXPR:TYPE[E2]≠scalar_VALUE THEN ERROR(109, "Type mismatch.");
EXPR:OP[CUR_EXPR]←"SSUB";
EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
β
ELSE IF EXPR:TYPE[E1]=vector_VALUE THEN
α
IF EXPR:TYPE[E2]=vector_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"VSUB";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
β
ELSE IF EXPR:TYPE[E2]=trans_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"TVSUB";
EXPR:TYPE[CUR_EXPR]←trans_VALUE;
β
β
ELSE ERROR(109,"Type mismatch");
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
! times_R;
procedure times_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "*" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E2]=vector_VALUE THEN α E3←E1; E1←E2; E2←E3; β;
TEMP←NEW_RECORD(EXPR_LIST);
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[TEMP]←E1;
EXPR_LIST:EXP[CUR_PARTS]←E2;
CUR_EXPR←NEW_RECORD(EXPR);
COMBINE(EXPR:UPPER_DIMEN[CUR_EXPR],EXPR:LOWER_DIMEN[CUR_EXPR],
EXPR:UPPER_DIMEN[E1],EXPR:LOWER_DIMEN[E1],EXPR:UPPER_DIMEN[E2],
EXPR:LOWER_DIMEN[E2]);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
IF EXPR:TYPE[E1]≤trans_VALUE
THEN CASE EXPR:TYPE[E1] OF
α "E1"
[scalar_VALUE] α
IF EXPR:TYPE[E2]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
EXPR:OP[CUR_EXPR]←"SMUL";
EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
β;
[vector_VALUE] IF EXPR:TYPE[E2]≤trans_VALUE
THEN CASE EXPR:TYPE[E2] OF
α "E2"
[scalar_VALUE] α
EXPR:OP[CUR_EXPR]←"SVMUL";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
β;
[vector_VALUE] ERROR(109,"Type mismatch.");
[rot_VALUE] α
EXPR:OP[CUR_EXPR]←"RVMUL";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
β;
[frame_VALUE] ERROR(109,"Type mismatch.");
[plane_VALUE] ERROR(109,"Type mismatch.");
[trans_VALUE] α
EXPR:OP[CUR_EXPR]←"TVMUL";
EXPR:TYPE[CUR_EXPR]←vector_VALUE;
β
β "E2"
ELSE ERROR(109,"Type mismatch.");
[rot_VALUE] α
IF EXPR:TYPE[E2]≠rot_VALUE THEN ERROR(109,"Type mismatch.");
EXPR:OP[CUR_EXPR]←"RRMUL";
EXPR:TYPE[CUR_EXPR]←rot_VALUE;
β;
[frame_VALUE] ERROR(120,"Type mismatch.");
[plane_VALUE] ERROR(120,"Type mismatch.");
[trans_VALUE] α
IF EXPR:TYPE[E2]≠trans_VALUE THEN ERROR(109,"Type mismatch.");
EXPR:OP[CUR_EXPR]←"TTMUL";
EXPR:TYPE[CUR_EXPR]←trans_VALUE;
β
β "E1"
ELSE ERROR(109,"Type mismatch");
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
! rot_R, wrt_R;
procedure rot_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "ROT" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
EXPRS←EXPR_LIST:NEXT[EXPRS];
IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E2]≠vector_VALUE THEN ERROR(109,"Type mismatch.");
TEMP←NEW_RECORD(EXPR_LIST);
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[TEMP]←E1;
EXPR_LIST:EXP[CUR_PARTS]←E2;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:OP[CUR_EXPR]←"AXW_ROTN";
EXPR:TYPE[CUR_EXPR]←rot_VALUE;
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
procedure wrt_R;
α RECORD_POINTER (OP_LIST) OP_SAVE;
COMMENT
vector WRT frame
GETS TRANSLATED TO
(TVMUL (ORIENT frame) vector)
SO THIS PROCEDURE MERELY CHAANGES THE TOP OF THE OP_LIST
DOING NO REAL REDUCTION. THE REDUCTION IS THEN DONE ON THE
FOLLOWING TWO PASSES. (NOTE: THIS MEANS THAT THE PRECEDENCE
OF WRT IS DIFFERENT DEPENDING ON WHICH SIDE YOU SEE IT FROM.
;
OP_LIST:OP[OPS]←times_X;
OPSAVE←OPS;
OPS←NEW_RECORD(OP_LIST);
OP_LIST:NEXT[OPS]←OPSAVE;
OP_LIST:PRIORITY[OPS]← SPECIAL_INFO;
OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[orient_X];
OP_LIST:FUNC[OPS]←FALSE;
OP_LIST:ARG_DEP[OPS]←OP_BOOL[orient_X];
OP_LIST:OP[OPS]←orient_X;
COMMENT NOTE THAT THE END OF REDUCE (where the execution goes next)
WILL THROW AWAY THE TOP OP ON OP_LIST, SO WE'RE GOING TO
PUT ON A DUMMY OPERATOR;
OPSAVE←OPS;
OPS←NEW_RECORD(OP_LIST);
OP_LIST:NEXT[OPS]←OPSAVE;
β;
! →_R;
procedure →_R;
α RECORD_POINTER (EXPR_LIST) CUR_PARTS,TEMP; ! "→" FOUND;
RECORD_POINTER (EXPR) CUR_EXPR,E1,E2,E3;
IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
E1←EXPR_LIST:EXP[EXPRS];
EXPRS←EXPR_LIST:NEXT[EXPRS];
IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
E2←EXPR_LIST:EXP[EXPRS];
IF EXPR:TYPE[E1]≠EXPR:TYPE[E2] THEN ERROR(111,"Type mismatch.");
TEMP←NEW_RECORD(EXPR_LIST);
CUR_PARTS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
EXPR_LIST:EXP[TEMP]←E1;
EXPR_LIST:EXP[CUR_PARTS]←E2;
CUR_EXPR←NEW_RECORD(EXPR);
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
COMBINE(EXPR:UPPER_DIMEN[CUR_EXPR],EXPR:LOWER_DIMEN[CUR_EXPR],
EXPR:UPPER_DIMEN[E1],EXPR:LOWER_DIMEN[E1],EXPR:LOWER_DIMEN[E2],
EXPR:UPPER_DIMEN[E2]);
IF EXPR:TYPE[E1]=vector_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"VTOV";
EXPR:TYPE[CUR_EXPR]←rot_VALUE;
β
ELSE IF EXPR:TYPE[E1]=trans_VALUE THEN
α
EXPR:OP[CUR_EXPR]←"FTOF";
EXPR:TYPE[CUR_EXPR]←trans_VALUE;
β
ELSE ERROR(109,"Type mismatch");
EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
β;
! reduce execution starts here;
CUR_OP_NUM←OP_LIST:OP[OPS];
IF ¬(1 ≤ CUR_OP_NUM ≤ op_count)
THEN FAIL_UP(1030,"Trying to parse expression and found garbage.");
IF OP_BOOL[CUR_OP_NUM] THEN
CASE CUR_OP_NUM - first_true_op OF
α
redefine xx(str1, i1, boole, i2, i3, i4, str2)=[
ifc boole
thenc
redefine xx_temp=ifc "str2"=null thenc [str1] elsec [str2] endc & "_R";
xx_temp;
endc ];
operator_definitions;
β
ELSE α RECORD_POINTER(EXPR_LIST) CUR_PARTS,TEMP;
RECORD_POINTER (EXPR) CUR_EXPR;
INTEGER I;
FOR I←1 STEP 1 UNTIL OP_NUM[CUR_OP_NUM] DO
α
IF EXPRS=NULL_RECORD THEN FAIL_UP(107,"Can't reduce expression.");
TEMP←EXPRS;
EXPRS←EXPR_LIST:NEXT[EXPRS];
EXPR_LIST:NEXT[TEMP]←CUR_PARTS;
CUR_PARTS←TEMP;
IF TYPE_OF_ARGS[CUR_OP_NUM]≠EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]]
AND TYPE_OF_ARGS[CUR_OP_NUM]≥0
THEN ERROR(108,"Type mismatch");
β;
CUR_EXPR←NEW_RECORD(EXPR);
CASE DIMEN_CHANGES[CUR_OP_NUM] OF
α
[ignore_dimen] ;
[same_dimen] α
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]];
β;
[inverse_dimen] α
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]];
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]];
β;
[check_dimen] α RECORD_POINTER(EXPR) E1,E2;
E1←EXPR_LIST:EXP[CUR_PARTS];
E2←EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]];
CHECK("expression",EXPR:UPPER_DIMEN[E1],EXPR:LOWER_DIMEN[E1],EXPR:UPPER_DIMEN[E2],
EXPR:LOWER_DIMEN[E2]);
EXPR:UPPER_DIMEN[CUR_EXPR]←EXPR:UPPER_DIMEN[E1];
EXPR:LOWER_DIMEN[CUR_EXPR]←EXPR:LOWER_DIMEN[E1];
β;
[multiply_dimen] COMBINE(EXPR:UPPER_DIMEN[CUR_EXPR],EXPR:LOWER_DIMEN[CUR_EXPR],
EXPR:UPPER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
EXPR:LOWER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
EXPR:UPPER_DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]],
EXPR:LOWER_DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]]);
[divide_dimen] COMBINE(EXPR:UPPER_DIMEN[CUR_EXPR],EXPR:LOWER_DIMEN[CUR_EXPR],
EXPR:UPPER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
EXPR:LOWER_DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
EXPR:LOWER_DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]],
EXPR:UPPER_DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]])
β;
EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
EXPR:OP[CUR_EXPR]←OP_ARRAY[CUR_OP_NUM];
IF RESULT_TYPE[CUR_OP_NUM]≥0 THEN
EXPR:TYPE[CUR_EXPR]←RESULT_TYPE[CUR_OP_NUM] ELSE
EXPR:TYPE[CUR_EXPR]←EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]];
TEMP←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[TEMP]←EXPRS;
EXPR_LIST:EXP[TEMP]←CUR_EXPR;
EXPRS←TEMP;
β;
RAISE: OPS←OP_LIST:NEXT[OPS];
β;
! printexpr;
RECURSIVE PROCEDURE PRINTEXPR(RECORD_POINTER (EXPR) E);
IF EQU(EXPR:OP[E],null) THEN OUTEXPR←OUTEXPR&EXPR:ID[E]
ELSE α RECORD_POINTER (EXPR_LIST) SUBS;
OUTEXPR←OUTEXPR&"("&EXPR:OP[E];
SUBS←EXPR:PARTS[E];
WHILE SUBS≠NULL DO
α
OUTEXPR←OUTEXPR&" ";
PRINTEXPR(EXPR_LIST:EXP[SUBS]);
SUBS←EXPR_LIST:NEXT[SUBS];
β;
OUTEXPR←OUTEXPR&")";
β;
! p_exp2;
! PARSE EXPRESSIONS AND SAVE PARSED STRUCTURE INTERNALLY FOR LATER PRINTING;
PROCEDURE P_EXP2;
α RECORD_POINTER (ID_LIST) POINT; LABEL FLUSH;
PROCEDURE F_EXP(INTEGER IP; STRING SP);
α RECORD_POINTER(EXPR)E;
ERROR(IP,SP&crlf&"Continue will attempt to flush expression.");
WHILE ( TYPE_OF_TOKEN=id_token
OR (EQU(TOKEN,"(") AND ¬OP_EXPECTED)
OR TYPE_OF_TOKEN=numeric_token
OR (TYPE_OF_TOKEN=special_token
AND ((operator_beg ≤ TYPE_OF_RES_WORD ≤ operator_end)
OR TYPE_OF_RES_WORD=declare_RES)))
DO GET_TOKEN;
OPS←NULL_RECORD;
if exprs≠null_record then
α
E←NEW_RECORD(EXPR);
EXPR:TYPE[E]←scalar_VALUE;
EXPR:ID[E]←"GARB_ID";
EXPR_LIST:NEXT[EXPRS]←NULL_RECORD;
EXPR_LIST:EXP[EXPRS]←E;
β;
GO TO FLUSH;
β;
! parse_special;
procedure parse_special;
α "parse_special" integer j;
define expected_ops=[
xx([(], -1, -1, false, false)
xx([|], sabs_X, -1, true, false)
xx([-], sneg_X, vector_RES, false, false)
xx([/], rinv_X, vector_RES, false, false)
xx(NOT, not_X, not_RES, false, false)
xx([¬], not_X, not_RES, false, false)
xx(VVTRANS, vvtrans_X, vector_RES, false, true)
xx(ROT, rot_X, vector_RES, true, true)
xx(VVROT, vvrot_X, vector_RES, false, true)
xx(VDOT, vdot_X, vector_RES, false, true)
xx(ANGLE, angle_X, vector_RES, false, true)
];
define
op_case=0;
redefine xx(token, op_num, prior, arg_dep, func)=[
redefine op_case=op_case+1;];
expected_ops;
redefine xx(token, op_num, prior, arg_dep, func)=["token",];
preload_array(
expected_name, expected_ops, [own string], 0, op_case);
redefine xx(token, op_num, prior, arg_dep, func)=[op_num,];
preload_array(
expected_X, expected_ops, [own integer], 0, op_case);
redefine xx(token, op_num, prior, arg_dep, func)=[prior,];
preload_array(
expected_prior, expected_ops, [own integer], 0, op_case);
redefine xx(token, op_num, prior, arg_dep, func)=[arg_dep,];
preload_array(
expected_arg, expected_ops, [own boolean], 0, op_case);
redefine xx(token, op_num, prior, arg_dep, func)=[func,];
preload_array(
expected_func, expected_ops, [own boolean], 0, op_case);
OPSAVE←OPS; OPS←NEW_RECORD(OP_LIST);
OP_LIST:NEXT[OPS]←OPSAVE;
OP_LIST:PRIORITY[OPS] ← SPECIAL_INFO;
for j←0 step 1 until op_case-1 do if equ(token,expected_name[j]) then done;
if j ≤ op_case-1
then
α integer k;
OP_LIST:PRIORITY[OPS] ← expected_prior[j];
OP_LIST:OP[OPS] ← k ← expected_X[j];
OP_LIST:NUM_OF_ARGS[OPS] ← if k<0 then 1 else op_num[k];
op_list:count[ops] ← 0;
OP_LIST:ARG_DEP[OPS] ← expected_arg[j];
op_list:func[ops] ← expected_func[j];
β
ELSE IF EQU(TOKEN,"⊗")
THEN
α
EXP1←NEW_RECORD(EXPR);
EXPR:TYPE[EXP1]←trans_VALUE;
EXPR:OP[EXP1]←null;
IF EQU(CURRENT_FRAME,null) THEN
ERROR(1111,"⊗ used outside of MOVE, AFFIX, or UNAFFIX statement is illegal.");
EXPR:ID[EXP1]←CURRENT_FRAME;
EXPR:UPPER_DIMEN[EXP1]←distance_dimens;
EXPRSAVE←EXPRS;
EXPRS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
EXPR_LIST:EXP[EXPRS]←EXP1;
OPS←OP_LIST:NEXT[OPS];
OP_EXPECTED←TRUE;
β
ELSE IF TYPE_OF_RES_WORD=declare_RES
THEN
α "declare_RES"
case special_info of
α "special_info"
[vector_VALUE] α ! VMAKE FOUND;
OP_LIST:OP[OPS] ← vmake_X;
OP_LIST:NUM_OF_ARGS[OPS] ← op_num[vmake_X];
β;
[frame_VALUE] α ! FMAKE FOUND;
OP_LIST:OP[OPS] ← fmake_X;
OP_LIST:NUM_OF_ARGS[OPS] ← op_num[fmake_X];
β;
[trans_VALUE] α ! TMAKE FOUND;
OP_LIST:OP[OPS] ← tmake_X;
OP_LIST:NUM_OF_ARGS[OPS] ← op_num[tmake_X];
β;
[0] F_EXP(103,"Illegal operator.");
[scalar_VALUE] F_EXP(103,"Illegal operator.");
[rot_VALUE] F_EXP(103,"Illegal operator.");
[plane_VALUE] F_EXP(103,"Illegal operator.")
β "special_info";
OP_LIST:COUNT[OPS]←0;
OP_LIST:ARG_DEP[OPS]←FALSE;
OP_LIST:FUNC[OPS]←TRUE;
β "declare_RES"
ELSE if special_info
then
α
OP_LIST:OP[OPS]←SPECIAL_INFO;
OP_LIST:ARG_DEP[OPS]←OP_BOOL[SPECIAL_INFO];
OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[SPECIAL_INFO];
β
else f_exp(200, "Doesn't make sense.");
β "parse_special";
! p_exp2 execution begins here, p_exp;
OP_EXPECTED←FALSE; EXPRS←ops←EXP1←EXP2←EXP3←NULL_RECORD; OUTEXPR←null;
GET_TOKEN;
WHILE ( TYPE_OF_TOKEN=id_token
OR (EQU(TOKEN,"(") AND ¬OP_EXPECTED)
OR TYPE_OF_TOKEN=numeric_token
OR (TYPE_OF_TOKEN=special_token
AND ((operator_beg ≤ TYPE_OF_RES_WORD ≤ operator_end)
OR TYPE_OF_RES_WORD=declare_RES)))
DO
α "while"
IF OP_EXPECTED THEN
α "op_expected"
IF EQU(TOKEN,"ROT") THEN
α
TYPE_OF_TOKEN←special_token;
TYPE_OF_RES_WORD←trans_RES;
SPECIAL_INFO←rot_X;
β;
IF TYPE_OF_TOKEN>special_token OR EQU(TOKEN,"(")
THEN F_EXP(101,"Operation needed here.");
α "termin_check" integer match, j; string str;
match ← -1; j←0;
for str ← ")", ",", "|" do
if equ(str, token)
then α match ← j; done β
else j ← j+1;
if match ≥ 0
then case match of
α "match"
! ")"; α
WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠-1 DO REDUCE;
IF OPS=NULL_RECORD THEN done "while";
OPS←OP_LIST:NEXT[OPS];
IF OPS≠NULL_RECORD AND OP_LIST:FUNC[OPS]=TRUE THEN REDUCE;
β;
! ","; α
WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠-1 DO REDUCE;
IF OPS=NULL THEN done "while";
OP_EXPECTED←FALSE;
β;
! "|"; α integer e;
WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠17 DO REDUCE;
IF OPS=NULL_RECORD
THEN F_EXP(105,"Mismatched vertical paren.");
OPS←OP_LIST:NEXT[OPS];
EXP1←NEW_RECORD(EXPR);
EXPR:PARTS[EXP1]←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[EXPR:PARTS[EXP1]]←EXPR_LIST:EXP[EXPRS];
EXPR:UPPER_DIMEN[EXP1]
← EXPR:UPPER_DIMEN[EXPR_LIST:EXP[EXPRS]];
EXPR:LOWER_DIMEN[EXP1]
← EXPR:LOWER_DIMEN[EXPR_LIST:EXP[EXPRS]];
EXPR:TYPE[EXP1]←scalar_VALUE;
IF (e ← EXPR:TYPE[EXPR_LIST:EXP[EXPRS]])=scalar_VALUE
THEN EXPR:OP[EXP1]←"SABS";
IF E=vector_VALUE THEN EXPR:OP[EXP1]←"VMAGN";
IF E=rot_VALUE THEN EXPR:OP[EXP1]←"RMAGN";
if e≠scalar_value or e≠vector_value or e≠rot_value
then ERROR(106,"Type mismatch for |.|.");
EXPR_LIST:EXP[EXPRS]←EXP1;
β
β "match"
ELSE
α
IF TYPE_OF_RES_WORD=0
THEN F_EXP(1000,"Sorry, OP not implemented yet.");
WHILE OPS≠NULL_RECORD AND OP_LIST:PRIORITY[OPS]≥TYPE_OF_RES_WORD
DO REDUCE;
OPSAVE←OPS;
OPS←NEW_RECORD(OP_LIST);
OP_LIST:NEXT[OPS]←OPSAVE;
OP_LIST:PRIORITY[OPS]←TYPE_OF_RES_WORD;
OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[SPECIAL_INFO];
OP_LIST:FUNC[OPS]←FALSE;
OP_LIST:ARG_DEP[OPS]←OP_BOOL[SPECIAL_INFO];
OP_LIST:OP[OPS]←SPECIAL_INFO;
OP_EXPECTED←FALSE;
β
β "termin_check"
β "op_expected"
ELSE case TYPE_OF_TOKEN of
α "type_of_token"
[id_token] α RECORD_POINTER (ID_LIST) PPPP;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE (POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN))
DO POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL THEN
α
ERROR(102,"Undefined ID "&TOKEN);
POINT ← SYMBOL_TABLE[HASH("GARB_ID",hasher)];
TOKEN←"GARB_ID";
β;
EXP1←NEW_RECORD(EXPR);
EXPR:TYPE[EXP1]←ID_LIST:TYPE[POINT];
EXPR:UPPER_DIMEN[EXP1]←DIMEN_DEFS[ID_LIST:DIMEN_P[POINT]];
EXPR:LOWER_DIMEN[EXP1]←DIMEN_DEFS2[ID_LIST:DIMEN_P[POINT]];
EXPR:OP[EXP1]←null;
EXPR:ID[EXP1]←TOKEN;
EXPRSAVE←EXPRS;
EXPRS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
EXPR_LIST:EXP[EXPRS]←EXP1;
OP_EXPECTED←TRUE;
β;
[numeric_token] α
EXP1←NEW_RECORD(EXPR);
EXPR:TYPE[EXP1]←scalar_VALUE;
EXPR:OP[EXP1]←null;
EXPR:ID[EXP1]←TOKEN;
EXPRSAVE←EXPRS;
EXPRS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
EXPR_LIST:EXP[EXPRS]←EXP1;
OP_EXPECTED←TRUE;
β;
[special_token] parse_special;
[string_token] F_EXP(100,"Illegal expression.")
β "type_of_token";
GET_TOKEN;
β "while";
FLUSH:
REJECT←TRUE;
WHILE OPS≠NULL_RECORD DO REDUCE;
IF EXPRS=NULL
THEN
α
ERROR(107,"Empty expression, continue will insert GARBID");
EXPRS←NEW_RECORD(EXPR_LIST);
EXPR_LIST:EXP[EXPRS]←NEW_RECORD(EXPR);
EXPR:ID[EXPR_LIST:EXP[EXPRS]]←"GARB_ID";
β
ELSE IF EXPR_LIST:NEXT[EXPRS]≠NULL THEN ERROR(107,"Can't reduce expression.");
UPPER_D←EXPR:UPPER_DIMEN[EXPR_LIST:EXP[EXPRS]];
LOWER_D←EXPR:LOWER_DIMEN[EXPR_LIST:EXP[EXPRS]];
PRINTEXPR(EXPR_LIST:EXP[EXPRS]);
EXP_TYPE←EXPR:TYPE[EXPR_LIST:EXP[EXPRS]];
β;
! PARSE EXPRESSIONS AND IMMEDIATELY PRINT EXPRESSION IN ALCODE FORM;
PROCEDURE P_EXP;
α
P_EXP2;
PRINT(OUTEXPR);
β;
! P_condition;
! CONDITION FINDER - NOT YET INCLUDED;
BOOLEAN PROCEDURE P_CONDITION(INTEGER PP;STRING PRELUDE);
α STRING COND,OP; LABEL FLUSH;
PROCEDURE F_STATE(VALUE INTEGER IP; VALUE STRING SP);
α STRING CLOSE; INTEGER I;
FOR I←1 STEP 1 UNTIL PP DO CLOSE←CLOSE&")";
SPACING←SPACING-PP;
PRINT(CLOSE);
ERROR(IP,SP&crlf&"Continue will flush statement.");
WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
REJECT←TRUE;
GO TO FLUSH;
β;
GET_TOKEN;
IF TYPE_OF_TOKEN≠special_token OR TYPE_OF_RES_WORD≠0 THEN
F_STATE(44,"Bogus condition monitor.");
IF SPECIAL_INFO=nil_CM
THEN COND←TOKEN
ELSE
α INTEGER FORCE_TYPE;
! YOU MIGHT WANT TO INCORPORATE ALL OF THIS INTO P_EXP2;
FORCE_TYPE←SPECIAL_INFO;
COND←"(FORCE ";
GET_TOKEN;
IF ¬EQU(TOKEN,"(") THEN
ERROR(1201,"Need left paren here. Continue will insert it.");
IF FORCE_TYPE=torque_CM
THEN COND←COND&"NILVECT "
ELSE
α
P_EXP2;
IF EXP_TYPE≠vector_VALUE THEN F_STATE(1202,"Need vector here.");
COND←COND&OUTEXPR&" ";
β;
IF FORCE_TYPE=force_or_torque_CM THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,",") THEN ERROR(1203,"Need comma here. Continue will insert it.");
β;
IF FORCE_TYPE=force_CM
THEN COND←COND&"NILVECT"
ELSE
α
P_EXP2;
IF EXP_TYPE≠vector_VALUE THEN F_STATE(1202,"Need vector here.");
COND←COND&OUTEXPR;
β;
GET_TOKEN;
IF ¬EQU(TOKEN,")") THEN
ERROR(1201,"Need right paren here. Continue will insert it.");
COND←COND&")";
β;
GET_TOKEN;
IF TYPE_OF_TOKEN≠special_token OR TYPE_OF_RES_WORD≠order_RES
THEN F_STATE(44,"Bogus condition monitor.");
OP←OP_ARRAY[SPECIAL_INFO];
PRINT(PRELUDE&" ("&OP&" "&COND);
SPACING←SPACING+1;
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN ERROR(49,"Need scalar quantity here.");
PRINT(")");
SPACING←SPACING-1;
RETURN(FALSE);
FLUSH: RETURN(TRUE);
β;
! P_clauses, T_gen;
PROCEDURE P_CLAUSES;
α BOOLEAN T; LABEL FLUSH;
PROCEDURE F_STATE(VALUE INTEGER IP; VALUE STRING SP);
α STRING CLOSE; INTEGER I;
SPACING←SPACING-2;
PRINT("))");
ERROR(IP,SP&crlf&"Continue will flush statement.");
WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
REJECT←TRUE;
GO TO FLUSH;
β;
T←TRUE;
GET_TOKEN;
WHILE T DO
IF TYPE_OF_TOKEN≠special_token THEN
α RECORD_POINTER (ID_LIST) POINT; STRING LABL;
! LABELED CONDITION MONITOR FOUND;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠cm_label_VALUE THEN
ERROR(51,"Illegal or undefined ID. Can only handle Condition Monitor ID here.");
LABL←TOKEN&" ";
GET_TOKEN;
IF ¬EQU(TOKEN,":") THEN
ERROR_REJECT(53,"Need semicolon here. Continue will insert it.");
GET_TOKEN;
IF ¬EQU(TOKEN,"ON") THEN
ERROR_REJECT(52,"Need ON here for a condition monitor.");
P_CONDITION(2,"("&LABL&"ON");
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(45,"Need DO here. Continue will insert it.");
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
GET_TOKEN;
β
ELSE IF TYPE_OF_RES_WORD=on_RES THEN
α
! UNLABELED CONDITION MONITOR FOUND;
P_CONDITION(2,"("&"ON");
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(45,"Need DO here. Continue will insert it.");
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
GET_TOKEN;
β
ELSE IF EQU(TOKEN,"(") THEN
α INTEGER C; STRING TEMP;
! LEFT PAREN FOUND - STAIGHT TRANSFER;
C←1;
TEMP←"(";
WHILE C>0 DO
α
TEMP←TEMP&READ(paren_cr_break);
IF BRCHAR="(" THEN C←C+1
ELSE IF BRCHAR=")" THEN C←C-1 ELSE
α
PRINT(TEMP);
TEMP←NULL;
β;
β;
PRINT(TEMP);
GET_TOKEN;
β
ELSE IF ¬(move_beg ≤ TYPE_OF_RES_WORD ≤ move_end) THEN
α
! END OF MOVE STATEMENT FOUND;
REJECT←TRUE;
T←FALSE;
β
ELSE CASE TYPE_OF_RES_WORD - move_beg OF
α
[via_X] α
! VIA CLAUSE FOUND;
PRINT("(VIA ");
SPACING←SPACING+1;
P_EXP;
GET_TOKEN;
IF EQU(TOKEN,",") THEN
α;
SPACING←SPACING-1;
PRINT(")");
WHILE EQU(TOKEN,",") DO
α
PRINT("(VIA ");
SPACING←SPACING+1; P_EXP; SPACING←SPACING-1;
PRINT(")");
GET_TOKEN;
β;
β
ELSE α BOOLEAN V_FOUND,D_FOUND,CONTIN;
CONTIN←TRUE;
IF EQU(TOKEN,"WITH") THEN
WHILE ¬(V_FOUND ∧ D_FOUND) ∧ CONTIN DO
α
GET_TOKEN;
IF V_FOUND ∧ EQU(TOKEN,"VELOCITY") THEN
F_STATE(3011,"Multiple VELOCITY specification found in WITH clause.")
ELSE IF EQU(TOKEN,"VELOCITY") THEN
α
PRINT("(VELOCITY ");
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3014,"Need = here.");
SPACING←SPACING+1;
P_EXP;
SPACING←SPACING-1;
PRINT(")");
IF EXP_TYPE≠vector_VALUE THEN
α
SPACING←SPACING-1;
PRINT(")");
F_STATE(3012,"Need a vector expression here.");
β;
V_FOUND←TRUE;
GET_TOKEN;
IF ¬EQU(TOKEN,",") THEN CONTIN←FALSE;
β
ELSE IF D_FOUND ∧ EQU(TOKEN,"DURATION") THEN
F_STATE(3013,"Multiple DURATION specification found in WITH clause.")
ELSE IF EQU(TOKEN,"DURATION") THEN
α
GET_TOKEN;
IF ¬(EQU(TOKEN,"=") ∨ EQU(TOKEN,"<") ∨ EQU(TOKEN,">")) THEN
ERROR_REJECT(3014,"Need =,<, or > here.");
PRINT("(DURATION " & TOKEN & " ");
SPACING←SPACING+1;
P_EXP;
SPACING←SPACING-1;
PRINT(")");
IF EXP_TYPE≠scalar_VALUE THEN
α
SPACING←SPACING-1;
PRINT(")");
F_STATE(3012,"Need a scalar expression here.");
β;
D_FOUND←TRUE;
GET_TOKEN;
IF ¬EQU(TOKEN,",") THEN CONTIN←FALSE;
β
ELSE CONTIN←FALSE;
β;
IF EQU(TOKEN,"THEN") THEN
α;
PRINT("(THEN");
SPACING←SPACING+1;
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
GET_TOKEN;
β;
SPACING←SPACING-1;
PRINT(")");
β;
β;
[with_X] α;
GET_TOKEN;
IF TYPE_OF_TOKEN≠special_token THEN F_STATE(3017,"Illegal WITH clause.")
ELSE IF TYPE_OF_RES_WORD=arrival_RES THEN
α
PRINT("(" & TOKEN);
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3022,"Need = here.");
GET_TOKEN;
IF EQU(TOKEN,"NILDEPROACH") THEN PRINT("NILDEPROACH")
ELSE IF EQU(TOKEN,"DEPROACH") THEN
α
PRINT("(DEPR");
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"(") THEN ERROR_REJECT(3019,"Need left paren here.");
P_EXP;
IF EXP_TYPE≠frame_exp_VALUE THEN F_STATE(3020,"Need frame exp here.");
GET_TOKEN;
IF ¬EQU(TOKEN,")") THEN ERROR_REJECT(3021,"Need right paren here.");
SPACING←SPACING-1;
PRINT(")");
β
ELSE α
REJECT←TRUE;
P_EXP;
IF EXP_TYPE≠scalar_VALUE ∧ EXP_TYPE≠vector_VALUE ∧ EXP_TYPE≠trans_VALUE THEN
ERROR(3018,"Type mismatch for DEPROACH.");
β;
SPACING←SPACING-1;
PRINT(")");
β
ELSE IF EQU(TOKEN,"WOBBLE") THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3022, "Need = here.");
PRINT("(WOBBLE ");
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN F_STATE(3012,"Need a scalar expression here.");
SPACING←SPACING - 1;
PRINT(")");
β
ELSE IF EQU(TOKEN,"FORCE") THEN F_STATE(3015,"SORRY, CAN'T HANDLE FORCE " &
"CLAUSES YET.")
ELSE IF EQU(TOKEN,"DURATION") THEN
α;
GET_TOKEN;
IF ¬(EQU(TOKEN,"=") ∨ EQU(TOKEN,"<") ∨ EQU(TOKEN,">")) THEN
ERROR_REJECT(3014,"Need =,<, or > here.");
PRINT("(DURATION " & TOKEN & " ");
SPACING←SPACING+1;
P_EXP;
SPACING←SPACING-1;
PRINT(")");
IF EXP_TYPE≠scalar_VALUE THEN
F_STATE(3012,"Need a scalar expression here.");
β
ELSE F_STATE(3016,"Illegal WITH clause.");
GET_TOKEN;
β
β;
FLUSH:
β;
STRING PROCEDURE T_GEN;
α
T_COUNT←T_COUNT+1;
RETURN("_T"&CVS(T_COUNT));
β;
! P_statement, begin_P;
RECURSIVE PROCEDURE P_STATEMENT;
α "P_STATEMENT"
LABEL FLUSH,TRY_AGAIN; STRING LABL; INTEGER LABEL_TYPE;
PROCEDURE F_STATE(VALUE INTEGER PP,IP; VALUE STRING SP);
α STRING CLOSE; INTEGER I;
FOR I←1 STEP 1 UNTIL PP DO CLOSE←CLOSE&")";
SPACING←SPACING-PP;
PRINT(CLOSE);
ERROR(IP,SP&crlf&"Continue will flush statement.");
WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
REJECT←TRUE;
GO TO FLUSH;
β;
procedure begin_P;
α INTEGER SAVE_DEC_NUM;
BLOCK_LEVEL←BLOCK_LEVEL+1;
SAVE_DEC_NUM←DEC_NUM; DEC_NUM←0;
PRINT("("&LABL&"BL");
SPACING←SPACING+1;
WHILE ¬EQU(TOKEN,"END") DO
α
P_STATEMENT;
GET_TOKEN;
IF TYPE_OF_TOKEN≠special_token OR TYPE_OF_RES_WORD≠end_RES
THEN ERROR_REJECT(4,
"Need semicolon before this token ⊂"&TOKEN&"⊃")
ELSE IF EQU(TOKEN,"COEND") THEN
α
ERROR(5,"Block ends with COEND" & cr
& "Continue to view as end");
TOKEN←"END";
β;
β;
FOR I←1 STEP 1 UNTIL DEC_NUM DO
α
SYMBOL_TABLE[HASH(ID_LIST:NAME[TOP_ID],hasher)]
← ID_LIST:NEXT[TOP_ID];
TOP_ID←ID_LIST:LINK[TOP_ID];
β;
DEC_NUM←SAVE_DEC_NUM;
SPACING←SPACING-1;
BLOCK_LEVEL←BLOCK_LEVEL-1;
PRINT(")");
β;
! cobegin_P, end_P, open_paren_P;
procedure cobegin_P;
α INTEGER SAVE_DEC_NUM; ! "COBEGIN" INDICATES BEGINNING OF COBLOCK;
BLOCK_LEVEL←BLOCK_LEVEL+1;
SAVE_DEC_NUM←DEC_NUM; DEC_NUM←0;
PRINT("("&LABL&"CO");
SPACING←SPACING+1;
WHILE ¬EQU(TOKEN,"COEND") DO
α
P_STATEMENT;
GET_TOKEN;
IF TYPE_OF_TOKEN≠special_token OR TYPE_OF_RES_WORD≠END_RES
THEN ERROR_REJECT(4,"Need semicolon before this token ⊂"
& TOKEN & "⊃")
ELSE IF EQU(TOKEN,"END") THEN
α
ERROR(5,"Block ends with END" & cr
& "Continue to view as COEND");
TOKEN←"COEND";
β;
β;
FOR I←1 STEP 1 UNTIL DEC_NUM DO
α
SYMBOL_TABLE[HASH(ID_LIST:NAME[TOP_ID],hasher)]←ID_LIST:NEXT
[TOP_ID];
TOP_ID←ID_LIST:LINK[TOP_ID];
β;
DEC_NUM←SAVE_DEC_NUM;
SPACING←SPACING-1;
BLOCK_LEVEL←BLOCK_LEVEL-1;
PRINT(")");
β;
procedure end_P;
α ! SEMICOLON FOUND - NOOP;
REJECT←TRUE;
β;
procedure open_paren_P;
α INTEGER C; STRING TEMP;
! LEFT PAREN FOUND - STAIGHT TRANSFER;
C←1;
TEMP←"(";
WHILE C>0 DO
α
TEMP←TEMP&READ(paren_cr_break);
IF BRCHAR="(" THEN C←C+1
ELSE IF BRCHAR=")" THEN C←C-1 ELSE
α
PRINT(TEMP);
TEMP←NULL;
β;
β;
PRINT(TEMP);
β;
! declare_P;
procedure declare_P;
α
STRING BUILD_OUT; INTEGER TYPE1; INTEGER DIM;
INTEGER DECLARE_TOKEN;
integer procedure find_special_info(string tok);
α "find_special_info"
integer point,VAL;
point←hash(tok,hasher);
WHILE ¬EQU(RESERVED[POINT],NULL) AND ¬EQU(RESERVED[POINT],tok) DO
POINT←(POINT+1)MOD hasher;
IF RESERVED[POINT]=TOK
THEN
α
VAL←COM_TYPE[POINT];
IF VAL≥hasher
THEN VAL←(VAL DIV hasher)
ELSE VAL←0;
β;
RETURN(VAL);
β "find_special_info";
procedure default_metric;
α
IF DECLARE_TOKEN= frame_VALUE
THEN DIM←FIND_SPECIAL_INFO("DISTANCE") ELSE DIM←0;
β;
BUILD_OUT←"("&LABL&DEC_NAME[SPECIAL_INFO];
DECLARE_TOKEN←SPECIAL_INFO;
IF SPECIAL_INFO≠frame_VALUE
THEN TYPE1←SPECIAL_INFO ELSE TYPE1←trans_VALUE;
GET_TOKEN;
IF TYPE_OF_TOKEN=special_token AND TYPE_OF_RES_WORD=metric_RES THEN
α
DIM←SPECIAL_INFO;
GET_TOKEN;
β
ELSE DEFAULT_METRIC;
WHILE ¬EQU(TOKEN,";") DO
α RECORD_POINTER (ID_LIST) POINT,SCAN_POINT;
INTEGER INDEX;
IF TYPE_OF_TOKEN≠id_token THEN F_STATE(0,6,"Illegal token or attempt "
&"to declare reserved word.");
INDEX←HASH(TOKEN,hasher);
SCAN_POINT←SYMBOL_TABLE[INDEX];
WHILE SCAN_POINT≠NULL_RECORD AND
ID_LIST:BLOCK_LEVEL_OF_DEFN[SCAN_POINT]=BLOCK_LEVEL DO
α
IF EQU(ID_LIST:NAME[SCAN_POINT],TOKEN) THEN
ERROR(3001,"⊂"&TOKEN&"⊃ is multiply defined "
&"in this block.");
SCAN_POINT←ID_LIST:NEXT[SCAN_POINT];
β;
BUILD_OUT←BUILD_OUT&" "&TOKEN;
POINT←NEW_RECORD(ID_LIST);
ID_LIST:NAME[POINT]←TOKEN;
ID_LIST:TYPE[POINT]←TYPE1;
ID_LIST:DIMEN_P[POINT]←DIM;
ID_LIST:BLOCK_LEVEL_OF_DEFN[POINT]←BLOCK_LEVEL;
ID_LIST:NEXT[POINT]←SYMBOL_TABLE[INDEX];
SYMBOL_TABLE[INDEX]←POINT;
ID_LIST:LINK[POINT]←TOP_ID;
TOP_ID←POINT;
DEC_NUM←DEC_NUM+1;
GET_TOKEN;
IF EQU(TOKEN,";") THEN REJECT←TRUE
ELSE IF ¬EQU(TOKEN,",") THEN
ERROR_REJECT(7,"Missing comma.");
GET_TOKEN;
β;
REJECT←TRUE;
PRINT(BUILD_OUT&")");
β;
! global_P;
procedure global_P;
α INTEGER O_DIM;
PRINT("("&LABL&"GVAR"); SPACING←SPACING+1; GET_TOKEN;
IF TYPE_OF_TOKEN=special_token AND TYPE_OF_RES_WORD=metric_RES
THEN α O_DIM←SPECIAL_INFO; GET_TOKEN; β;
WHILE ¬EQU(TOKEN,";") DO
α STRING BUILD_OUT; INTEGER TYPE1; INTEGER DIM;
DIM←O_DIM;
IF TYPE_OF_RES_WORD≠declare_RES
THEN F_STATE(1,8,"Need variable type here.");
TYPE_OF_RES_WORD←-1; ! reset to get WHILE LOOP started;
BUILD_OUT←"("&DEC_NAME[SPECIAL_INFO]; TYPE1←SPECIAL_INFO;
GET_TOKEN;
IF TYPE_OF_TOKEN=special_token AND TYPE_OF_RES_WORD=metric_RES
THEN α DIM←SPECIAL_INFO; GET_TOKEN; β;
WHILE ¬EQU(TOKEN,";")AND TYPE_OF_RES_WORD≠declare_RES DO
α RECORD_POINTER (ID_LIST) POINT,SCAN_POINT;
INTEGER INDEX;
IF TYPE_OF_TOKEN≠id_token THEN F_STATE(1,6,"Illegal token"
&" or attempt to declare reserved word.");
INDEX←HASH(TOKEN,hasher);
WHILE SCAN_POINT≠NULL_RECORD AND
ID_LIST:BLOCK_LEVEL_OF_DEFN[SCAN_POINT]=BLOCK_LEVEL DO
α
IF EQU(ID_LIST:NAME[SCAN_POINT],TOKEN) THEN
ERROR(3001,"⊂"&TOKEN&"⊃ is multiply defined "
&"in this block.");
SCAN_POINT←ID_LIST:NEXT[SCAN_POINT];
β;
BUILD_OUT←BUILD_OUT&" "&TOKEN;
POINT←NEW_RECORD(ID_LIST);
ID_LIST:NAME[POINT]←TOKEN;
ID_LIST:TYPE[POINT]←TYPE1;
ID_LIST:DIMEN_P[POINT]←DIM;
ID_LIST:BLOCK_LEVEL_OF_DEFN[POINT]←BLOCK_LEVEL;
ID_LIST:NEXT[POINT]←SYMBOL_TABLE[INDEX];
SYMBOL_TABLE[INDEX]←POINT;
ID_LIST:LINK[POINT]←TOP_ID;
TOP_ID←POINT;
DEC_NUM←DEC_NUM+1;
GET_TOKEN;
IF EQU(TOKEN,";")OR TYPE_OF_RES_WORD=declare_RES
THEN REJECT←TRUE
ELSE IF ¬EQU(TOKEN,",")
THEN ERROR_REJECT(7,"Missing comma.");
GET_TOKEN;
β;
PRINT(BUILD_OUT&")");
β;
REJECT←TRUE;
SPACING←SPACING-1;
PRINT(")");
β;
! if_P, plan_P, while_P;
procedure if_P;
α ! IF STATEMENT FOUND;
IF PLAN_STATEMENT THEN PRINT("("&LABL&"CIF") ELSE PRINT("("&LABL&"IF");
PLAN_STATEMENT←FALSE;
SPACING←SPACING+1;
P_EXP;
IF EXP_TYPE≠boole_VALUE AND EXP_TYPE≠scalar_VALUE
THEN F_STATE(1,10,"Conditional for IF must be boolean");
GET_TOKEN;
IF ¬EQU(TOKEN,"THEN") THEN
ERROR_REJECT(9,"Missing THEN. Continue will insert it.");
P_STATEMENT;
GET_TOKEN;
IF EQU(TOKEN,"ELSE") THEN P_STATEMENT ELSE REJECT←TRUE;
SPACING←SPACING-1;
PRINT(")");
β;
procedure plan_P;
α ! PLAN STATEMENT FOUND;
GET_TOKEN;
REJECT←TRUE;
PLAN_STATEMENT←TRUE;
IF ¬(EQU(TOKEN,"IF") OR EQU(TOKEN,"WRITE") OR EQU(TOKEN,"ERROR")
OR EQU(TOKEN,"FOREACH")) THEN F_STATE(0,11,"Illegal token to "&
"follow PLAN: "&TOKEN);
P_STATEMENT;
PLAN_STATEMENT←FALSE;
β;
procedure while_P;
α ! WHILE STATEMENT FOUND;
PRINT("("&LABL&"WH");
SPACING←SPACING+1;
P_EXP;
IF EXP_TYPE≠boole_VALUE AND EXP_TYPE≠scalar_VALUE
THEN F_STATE(0,11,"Conditional for WHILE must be boolean or sclar.");
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(12,"Missing DO. Continue will insert it.");
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
β;
! for_P;
procedure for_P;
α RECORD_POINTER(ID_LIST) POINT; ! FOR STATEMENT FOUND;
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(13,"Need scalar ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠scalar_VALUE THEN
α
ERROR(13,"Need scalar ID here.");
POINT ← SYMBOL_TABLE[HASH("GARB_ID",hasher)];
β;
PRINT("("&LABL&"FO "&ID_LIST:NAME[POINT]);
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"←") THEN
ERROR_REJECT(14,"Need left arrow here for FOR statement.");
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN
ERROR_REJECT(15,"Need scalar value here.");
GET_TOKEN;
IF ¬EQU(TOKEN,"STEP") THEN
ERROR_REJECT(16,"Need STEP here.");
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN
ERROR_REJECT(15,"Need scalar value here.");
GET_TOKEN;
IF ¬EQU(TOKEN,"UNTIL") THEN
ERROR_REJECT(17,"Need UNTIL here.");
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN
ERROR_REJECT(15,"Need scalar value here.");
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(18,"Need DO here.");
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
β;
! move_P;
procedure move_P;
α RECORD_POINTER(ID_LIST) POINT; ! MOVE STATEMENT FOUND;
GET_TOKEN;
IF EQU(TOKEN,"BLUE") THEN TOKEN←"BARM"
ELSE IF EQU(TOKEN,"YELLOW") THEN TOKEN←"YARM" ELSE
α
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need frame ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need frame ID here.");
β;
CURRENT_FRAME←TOKEN;
PRINT("("&LABL&"MO "&TOKEN);
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"TO") THEN
ERROR_REJECT(19,"Need TO here.");
P_EXP;
IF EXP_TYPE≠trans_VALUE THEN
ERROR_REJECT(20,"Need either a FRAME or TRANSFORM expression here.");
CURRENT_FRAME←null;
P_CLAUSES;
SPACING←SPACING-1;
PRINT(")");
β;
! affix_p;
procedure affix_p;
α STRING SAVE1,SAVE2,TRANS;
RECORD_POINTER(ID_LIST) POINT;
! AFFIX STATEMENT FOUND;
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN
ERROR_REJECT(19,"Need frame ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need frame ID here.");
CURRENT_FRAME←TOKEN;
SAVE1←TOKEN;
GET_TOKEN;
IF ¬EQU(TOKEN,"TO") THEN
ERROR_REJECT(21,"Need TO here. Continue will insert it.");
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need frame ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need frame ID here.");
SAVE2←TOKEN;
GET_TOKEN;
IF EQU(TOKEN,"BY") THEN
α
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need TRANS ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need trans ID here.");
TRANS←TOKEN;
β ELSE α
TRANS←T_GEN;
PRINT("(TVAR "&TRANS&")");
REJECT←TRUE;
β;
GET_TOKEN;
IF EQU(TOKEN,"AT") THEN
α
PRINT("("&LABL&"AFFIX "&SAVE1&" "&SAVE2&" "&TRANS);
SPACING←SPACING+1;
P_EXP;
GET_TOKEN;
IF EQU(TOKEN,"RIGIDLY")THEN PRINT("RIGIDLY)")
ELSE IF EQU(TOKEN,"NONRIGIDLY")THEN PRINT("NONRIGIDLY)")
ELSE α PRINT("NONRIGIDLY)");REJECT←TRUE; β;
SPACING←SPACING-1;
β ELSE α STRING HOW;
IF EQU(TOKEN,"RIGIDLY") OR EQU(TOKEN,"NONRIGIDLY") THEN
HOW←TOKEN ELSE α HOW←"NONRIGIDLY";REJECT←TRUE;β;
PRINT("("&LABL&"AFFIX "&SAVE1&" "&SAVE2&" "&TRANS&" () "&HOW&")");
β;
CURRENT_FRAME←null;
β;
! unfix_P, signal_P;
procedure unfix_P;
α STRING SAVE1;
RECORD_POINTER(ID_LIST) POINT;
! UNAFFIX STATEMENT FOUND;
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need frame ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need frame ID here.");
CURRENT_FRAME←TOKEN;
SAVE1←TOKEN;
GET_TOKEN;
IF ¬EQU(TOKEN,"FROM") THEN
ERROR_REJECT(20,"Need FROM here.");
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need frame ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠trans_VALUE THEN
ERROR(13,"Need frame ID here.");
PRINT("("&LABL&"UNFIX"&" "&SAVE1&" "&TOKEN&")");
CURRENT_FRAME←null;
β;
procedure signal_P;
α RECORD_POINTER(ID_LIST) POINT;
! SIGNAL STATEMENT FOUND;
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(19,"Need event ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠event_VALUE THEN
ERROR(21,"Need event ID here.");
PRINT("("&LABL&"EV "&TOKEN&" +)");
β;
! wait_P;
procedure wait_P;
α RECORD_POINTER(ID_LIST) POINT;
! WAIT STATEMENT FOUND;
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN ERROR(20,"Need event ID here.");
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE T AND POINT≠NULL DO
IF ID_LIST:NAME[POINT]=TOKEN THEN T←FALSE
ELSE POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠event_VALUE THEN
ERROR(21,"Need event ID here.");
PRINT("("&LABL&"EV "&TOKEN&" -)");
β;
! when_P;
procedure when_P;
α RECORD_POINTER (ID_LIST) POINT; STRING VAR, ALSO_OP, CHG_LAB;
BOOLEAN TEMP;
! WHEN STATEMENT FOUND;
GET_TOKEN;
IF ¬EQU(TOKEN,"CHANGING") THEN
ERROR_REJECT(30,"Need word CHANGING here for a WHEN CHANGING statement."&
" Continue will insert it.");
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL THEN ERROR(31,"Undefined ID");
VAR←TOKEN;
GET_TOKEN;
IF EQU(TOKEN,"ALSO") THEN ALSO_OP←"ALSO_DO"
ELSE IF EQU(TOKEN,"DON'T") THEN ALSO_OP←"ALSO_DON'T"
ELSE IF EQU(TOKEN,"ONLY") THEN ALSO_OP←"ALSO_ONLY"
ELSE ERROR(32,"Illegal ALSO_OP");
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(33,"Need DO here. Continue will insert it.");
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL THEN TEMP←TRUE
ELSE IF ID_LIST:TYPE[POINT]=ch_label_VALUE THEN TEMP←FALSE
! ?????; ELSE IF ID_LIST:TYPE[POINT]>world_VALUE THEN
α
ERROR(34,"Can only handle CH_LABEL here. Continue while delete this label.");
TEMP←TRUE;
β
ELSE TEMP←TRUE;
IF TEMP THEN
α
CHG_LAB←T_GEN;
PRINT("(CHGLAB "&CHG_LAB&")");
REJECT←TRUE;
CHANGER_HEAD←CHG_LAB&" CHG ";
β
ELSE α
CHG_LAB←TOKEN;
GET_TOKEN;
IF EQU(TOKEN,":") THEN
α
TEMP←TRUE;
CHANGER_HEAD←CHG_LAB&" CHG ";
β
ELSE α
REJECT←TRUE;
PRINT("("&ALSO_OP&" "&VAR&" "&CHG_LAB&")");
β;
β;
IF TEMP THEN
α
PRINT("("&ALSO_OP&" "&VAR);
SPACING←SPACING+1;
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
β;
β;
! dump_P;
procedure dump_P;
α RECORD_POINTER (ID_LIST) POINT; BOOLEAN T; STRING IDSTRING;
! DUMP STATEMENT FOUND;
IDSTRING←null;
GET_TOKEN;
T←TRUE;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT≠NULL AND ID_LIST:TYPE[POINT]=world_VALUE THEN
PRINT("("&LABL&"DBD "&TOKEN&")")
ELSE WHILE T DO
α
! ?????; IF POINT=NULL OR ID_LIST:TYPE[POINT]>event_VALUE THEN
ERROR(35,"Undefined ID.");
IDSTRING←IDSTRING&" "&TOKEN;
GET_TOKEN;
IF EQU(TOKEN,"IN") THEN T←FALSE
ELSE α
IF ¬EQU(TOKEN,",") THEN
ERROR_REJECT(36,"Need comma or IN here. Continue wil insert a comma.");
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
β;
β;
IF ¬T THEN
α
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠world_VALUE THEN
ERROR(37,"Need a world ID here.");
PRINT("("&LABL&"PVL "&IDSTRING&TOKEN&")");
β;
β;
! assert_P;
procedure assert_P;
α RECORD_POINTER (ID_LIST) POINT; STRING IDSTRING,COM;
INTEGER VAR_TYPE;
! ASSERT OR DENY STATEMENT FOUND;
COM←TOKEN;
GET_TOKEN;
IF EQU(TOKEN,"FORM") THEN
α
IDSTRING←null;
GET_TOKEN;
IF ¬EQU(TOKEN,"(") THEN
ERROR_REJECT(37,"Need left paren here. Continue will insert it.");
WHILE ¬EQU(TOKEN,")") DO
α
GET_TOKEN;
IDSTRING←IDSTRING&TOKEN&" ";
GET_TOKEN;
IF ¬EQU(TOKEN,")") AND ¬EQU(TOKEN,",") THEN
ERROR_REJECT(38,"Need either comma or right paren here."&
" Continue will insert a comma.");
β;
GET_TOKEN;
IF EQU(TOKEN,"IN") THEN
α
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠world_VALUE THEN
ERROR(39,"Need world ID here.");
PRINT("("&LABL&COM&" (SF "&IDSTRING&") "&TOKEN&")");
β
ELSE α
REJECT←TRUE;
PRINT("("&LABL&COM&" (SF "&IDSTRING&"))");
β;
β
ELSE α STRING VAR;
POINT←SYMBOL_TABLE[HASH(VAR←TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
! ?????; IF POINT=NULL OR ID_LIST:TYPE[POINT]>trans_VALUE THEN
α
ERROR(40,"Need variable ID here.");
POINT←SYMBOL_TABLE[HASH("GARB_ID",hasher)];
β;
VAR_TYPE←ID_LIST:TYPE[POINT];
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN ERROR(41,"Sorry, can only handle equality right now.");
PRINT("("&LABL&COM&" (AF "&VAR&" = ");
SPACING←SPACING+1;
P_EXP;
SPACING←SPACING-1;
IF VAR_TYPE≠EXP_TYPE THEN ERROR(42,"Types don't match on equality test.");
GET_TOKEN;
IF EQU(TOKEN,"IN") THEN
α
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠world_VALUE THEN
ERROR(39,"Need world ID here.");
PRINT(") "&TOKEN&")");
β
ELSE α
REJECT←TRUE;
PRINT("))");
β;
β;
β;
! on_P, reference_P, parseshit_P, open_P;
procedure on_P;
α RECORD_POINTER (ID_LIST) POINT;
! CONDITION MONITER FOUND;
IF ¬EQU(LABL,null) AND LABEL_TYPE≠cm_label_VALUE THEN
α
ERROR(43,"Must have condition monitor label if any label is uesed. Continue will flush label.");
LABL←null;
β;
P_CONDITION(0,"("&LABL&"ON");
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"DO") THEN
ERROR_REJECT(45,"Need DO here. Continue will insert it.");
P_STATEMENT;
SPACING←SPACING-1;
PRINT(")");
β;
procedure reference_P;
α RECORD_POINTER (ID_LIST) POINT; ! NEW WORLD DEF;
GET_TOKEN;
IF ¬EQU(TOKEN,"POINT") THEN
ERROR_REJECT(46,"Need POINT here for a REFERENCE POINT statement.");
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT=NULL OR ID_LIST:TYPE[POINT]≠world_VALUE THEN
ERROR(47,"Need a world variable here.");
PRINT("("&LABL&"NW "&TOKEN&")");
β;
procedure parseshit_P;
α ! PARSESHIT FOUND;
ifc debug_compile thenc BAIL; elsec usererr(0, 1, "Parseshit"); endc
β;
procedure open_P;
α STRING HAND; ! OPEN/CLOSE FOUND;
RECORD_POINTER (ID_LIST) POINT;
GET_TOKEN;
IF EQU(TOKEN,"BHAND") OR EQU(TOKEN,"YHAND") THEN HAND←TOKEN
ELSE IF EQU(TOKEN,"BLUE") THEN HAND←"BHAND"
ELSE IF EQU(TOKEN,"YELLOW") THEN HAND←"YHAND"
ELSE ERROR(48,"Unknown hand.");
GET_TOKEN;
IF ¬EQU(TOKEN,"TO") THEN
ERROR_REJECT(49,"Need TO here.");
PRINT("("&LABL&"MO "&HAND);
SPACING←SPACING+1;
P_EXP;
IF EXP_TYPE≠scalar_VALUE THEN ERROR(121,"Need scalar quantity here.");
SPACING←SPACING-1;
PRINT(")");
β;
! center_P, stop_P;
procedure center_P;
α ! CENTER FOUND;
GET_TOKEN;
IF EQU(TOKEN,"BLUE") THEN PRINT("("&LABL&"CENTER BARM)")
ELSE IF EQU(TOKEN,"YELLOW") THEN PRINT("("&LABL&"CENTER YARM)")
ELSE IF EQU(TOKEN,"YARM") OR EQU(TOKEN,"BARM") THEN PRINT("("&LABL&"CENTER "&TOKEN&")")
ELSE ERROR(48,"Unknown hand.");
β;
procedure stop_P;
α ! STOP FOUND;
GET_TOKEN;
IF EQU(TOKEN,"BLUE") THEN PRINT("("&LABL&"STOP BARM)")
ELSE IF EQU(TOKEN,"YELLOW") THEN PRINT("("&LABL&"STOP YARM)")
ELSE PRINT("("&LABL&"STOP "&TOKEN&")");
β;
! define_P;
procedure define_P;
α INTEGER PARAM_COUNT, HASH_ENTRY; STRING MACRO_NAME;
BOOLEAN SPECIAL_DELIMS; RECORD_POINTER (MACRO_LIST) MAC_POINT;
RECORD_POINTER (PARAM_LIST) TOP_PARAM, NEW_PARAM, LAST_PARAM;
procedure macro_delimiters(boolean turn_on);
α string chr1, chr2;
if turn_on
then if top_delimiters≠null_record
then
α
chr1 ← delimiter_list:d1[top_delimiters];
chr2 ← delimiter_list:d2[top_delimiters];
β
else chr1 ← chr2 ← dquote
else chr1 ← chr2 ← null;
delimiter_1 ← chr1; delimiter_2 ← chr2;
SETBREAK(macro_delimiter_break, chr1 & chr2, NULL, "ISN");
SETBREAK(word_R_break, TABLE1 & chr1, NULL, "INRK");
SETBREAK(word_S_break, TABLE1 & chr1, NULL, "INSK");
β;
do α "define_macro"
SPECIAL_DELIMS←FALSE; PARAM_COUNT←0; GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token
THEN F_STATE(0,56,"Can only define unreserved ID's.");
MACRO_NAME←TOKEN; GET_TOKEN;
IF EQU(TOKEN,"(") THEN
α "macro_parameters"
TOP_PARAM←LAST_PARAM←NEW_RECORD(PARAM_LIST);
WHILE ¬EQU(TOKEN,")") DO
α
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token
THEN F_STATE(0,57,"Can only use unreserved ID's as parameter names.");
PARAM_COUNT←PARAM_COUNT+1; NEW_PARAM←NEW_RECORD(PARAM_LIST);
PARAM_LIST:NEXT[LAST_PARAM]←NEW_PARAM;
PARAM_LIST:ID[NEW_PARAM]←TOKEN; LAST_PARAM←NEW_PARAM;
GET_TOKEN;
IF ¬EQU(TOKEN,")") AND ¬EQU(TOKEN,",") THEN
α
ERROR(58,"Need either comma or right paren here.");
REJECT←TRUE; TOKEN←")";
β;
β;
TOP_PARAM←PARAM_LIST:NEXT[TOP_PARAM];
GET_TOKEN;
β "macro_parameters";
IF TYPE_OF_TOKEN=string_token THEN
α "special_delimiters" RECORD_POINTER (DELIMITER_LIST) NEW_DEL;
SPECIAL_DELIMS←TRUE;
IF TYPE_OF_TOKEN≠string_token THEN F_STATE(0,52,"Need string here.");
IF LENGTH(TOKEN)≠2 THEN F_STATE(0,53,"Need string of length 2.");
push_delimiters(token);
β "special_delimiters";
IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(59,"Need = here.");
macro_delimiters(true); GET_TOKEN; macro_delimiters(false);
IF TYPE_OF_TOKEN≠string_token THEN F_STATE(0,60,"Need string here.");
MAC_POINT←NEW_RECORD(MACRO_LIST);
MACRO_LIST:ID[MAC_POINT]←MACRO_NAME;
MACRO_LIST:VALUE[MAC_POINT]←TOKEN;
MACRO_LIST:NUM[MAC_POINT]←PARAM_COUNT;
MACRO_LIST:PARAMS[MAC_POINT]←TOP_PARAM;
HASH_ENTRY←HASH(MACRO_NAME,hasher);
MACRO_LIST:NEXT[MAC_POINT]←MACRO_TABLE[HASH_ENTRY];
IF MACRO_TABLE[HASH_ENTRY]≠NULL THEN MACRO_LIST:LAST[MACRO_TABLE[HASH_ENTRY]]
←MAC_POINT;
MACRO_TABLE[HASH_ENTRY]←MAC_POINT;
IF SPECIAL_DELIMS THEN
α
IF NULL=TOP_DELIMITERS
THEN F_STATE(0,54,"Can't unstack special delimiters!");
TOP_DELIMITERS←DELIMITER_LIST:NEXT[TOP_DELIMITERS];
β;
get_token;
β "define_macro"
until ¬equ(token, ",");
if equ(token, ";") then reject ← true;
β;
! require_P;
procedure require_P;
α ! REQUIRE STATEMENT FOUND;
GET_TOKEN;
IF ¬(require_beg ≤ TYPE_OF_RES_WORD ≤ require_end)
THEN F_STATE(0,51, "Illegal token after require.")
ELSE
CASE TYPE_OF_RES_WORD - require_beg OF
α
[source_file_X] α RECORD_POINTER (SOURCE_LIST) NEW_SOURCE;
NEW_SOURCE←NEW_RECORD(SOURCE_LIST);
SOURCE_LIST:CHAN[NEW_SOURCE]←CHANIN;
SOURCE_LIST:NUM[NEW_SOURCE]←0;
SOURCE_LIST:FILE_NAME[NEW_SOURCE]←INFILE;
SOURCE_LIST:NEXT[NEW_SOURCE]←TOP_SOURCE;
TOP_SOURCE←NEW_SOURCE;
GET_TOKEN;
INFILE←TOKEN;
GET_TOKEN;
REJECT←TRUE;
SOURCE_LIST:PN[NEW_SOURCE]←PAGENUM;
SOURCE_LIST:LN[NEW_SOURCE]←LINENUM;
SOURCE_LIST:CUR_STRING[NEW_SOURCE]←CURLINE;
SOURCE_LIST:CUR_STRINGR[NEW_SOURCE]←CURLINER;
OPEN(CHANIN←GETCHAN,"DSK",0,4,0,COUNT,BRCHAR,EOF);
LOOKUP(CHANIN,INFILE,eof);
IF eof THEN
ERROR(55,"Lookup failed on required file - "&INFILE);
CURLINE←CURLINER←NULL; pagenum ← linenum ← 0;
if typed_page_num then outstr(crlf);
file_indent(sourcelvl ← sourcelvl+1);
outstr(infile & " 1"); typed_page_num ← true;
β;
[delimiters_X] α RECORD_POINTER (DELIMITER_LIST) NEW_DEL;
GET_TOKEN;
IF TYPE_OF_TOKEN≠string_token THEN F_STATE(0,52,"Need string here.");
IF LENGTH(TOKEN)≠2 THEN F_STATE(0,53,"Need string of length 2.");
push_delimiters(token);
β;
[unstack_delimiters_X] IF NULL=TOP_DELIMITERS
THEN F_STATE(0,54,"Sorry, delimiter stack empty.")
ELSE TOP_DELIMITERS←DELIMITER_LIST:NEXT[TOP_DELIMITERS];
[replace_delimiters_X] α
GET_TOKEN;
IF TYPE_OF_TOKEN≠string_token
THEN F_STATE(0,52,"Need string here.");
IF LENGTH(TOKEN)≠2
THEN F_STATE(0,53,"Need string of length 2.");
delimiter_list:d1[top_delimiters] ← lop(token);
delimiter_list:d2[top_delimiters] ← lop(token);
β
β;
β;
! dimension_P;
procedure dimension_P;
α ! DIMENSION STATEMENT FOUND;
INTEGER FILL_POINT; RECORD_POINTER(DIMENS_LIST) D1,D2,D3,D4,D5;
BOOLEAN TOP; INTEGER COUNT;
IF DIMEN_NUM≥16 THEN F_STATE(0,66,"Sorry, can't handle this many dimensions.");
TOP←TRUE; COUNT←0;
D1←D3←NEW_RECORD(DIMENS_LIST); D2←D4←NEW_RECORD(DIMENS_LIST);
GET_TOKEN;
IF TYPE_OF_TOKEN≠id_token THEN F_STATE(0,61,"Can only use unreserved ID's for dimensions.");
FILL_POINT←HASH(TOKEN,hasher);
WHILE RESERVED[FILL_POINT]≠NULL_RECORD DO FILL_POINT←(FILL_POINT+1)MOD hasher;
RESERVED[FILL_POINT]←TOKEN;
COM_TYPE[FILL_POINT]←metric_RES+hasher*(DIMEN_NUM+1);
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(62,"Need = here.");
GET_TOKEN;
WHILE ¬EQU(TOKEN,";") DO
α
IF EQU(TOKEN,"INV") THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,"(")
THEN ERROR_REJECT(63,"Need ( here.");
TOP←¬TOP;
COUNT←COUNT+1;
GET_TOKEN;
β;
IF TYPE_OF_RES_WORD≠metric_RES OR SPECIAL_INFO>metric_max
THEN F_STATE(0,64,"Need basic dimension here, e.g."
&" TIME, MASS, or ANGLE.");
D5←NEW_RECORD(DIMENS_LIST);
DIMENS_LIST:VALUE[D5]←SPECIAL_INFO;
IF TOP
THEN α DIMENS_LIST:NEXT[D3]←D5; D3←D5; β
ELSE α DIMENS_LIST:NEXT[D4]←D5; D4←D5; β;
GET_TOKEN;
IF EQU(TOKEN,"(") AND COUNT=0
THEN F_STATE(0,65,"Parens don't match.")
ELSE IF EQU(TOKEN,")") THEN COUNT←COUNT-1
ELSE IF EQU(TOKEN,";") AND COUNT≠0 THEN F_STATE(0,65,"Parens don't match.")
ELSE IF EQU(TOKEN,"/") THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,"(") THEN ERROR_REJECT(63,"Need ( here.");
TOP←¬TOP;
COUNT←COUNT+1;
β
ELSE IF ¬EQU(TOKEN,";") AND ¬EQU(TOKEN,"*") THEN
F_STATE(0,65,"Need ; here.");
IF ¬EQU(TOKEN,";") THEN GET_TOKEN;
β;
D5←DIMENS_LIST:NEXT[D1];
WHILE D5≠NULL_RECORD DO
α
D4←DIMENS_LIST:NEXT[D5];
WHILE D4≠NULL_RECORD DO
α INTEGER ITEMP;
IF DIMENS_LIST:VALUE[D5]>DIMENS_LIST:VALUE[D4] THEN
α
ITEMP←DIMENS_LIST:VALUE[D4];
DIMENS_LIST:VALUE[D4]←DIMENS_LIST:VALUE[D5];
DIMENS_LIST:VALUE[D5]←ITEMP;
β;
D4←DIMENS_LIST:NEXT[D4];
β;
D5←DIMENS_LIST:NEXT[D5];
β;
D5←DIMENS_LIST:NEXT[D2];
WHILE D5≠NULL_RECORD DO
α D4←DIMENS_LIST:NEXT[D5];
WHILE D4≠NULL_RECORD DO
α INTEGER ITEMP;
IF DIMENS_LIST:VALUE[D5]>DIMENS_LIST:VALUE[D4] THEN
α
ITEMP←DIMENS_LIST:VALUE[D4];
DIMENS_LIST:VALUE[D4]←DIMENS_LIST:VALUE[D5];
DIMENS_LIST:VALUE[D5]←ITEMP;
β;
D4←DIMENS_LIST:NEXT[D4];
β;
D5←DIMENS_LIST:NEXT[D5];
β;
DIMEN_NUM←DIMEN_NUM+1;
COMBINE(DIMEN_DEFS[DIMEN_NUM],DIMEN_DEFS2[DIMEN_NUM],DIMENS_LIST:NEXT[D1],
DIMENS_LIST:NEXT[D2],NULL_RECORD,NULL_RECORD);
REJECT←TRUE;
β;
! abort_P;
procedure abort_P;
α ! PRINT/ABORT/PAUSE STATEMENT FOUND;
IF EQU(TOKEN,"PAUSE") THEN
α
GET_TOKEN;
IF TYPE_OF_TOKEN≠numeric_token then F_STATE(0,1102,
"Need a numeric value here for a PAUSE statement.");
PRINT("(PAUSE "&TOKEN&")");
β
ELSE α
PRINT("("&TOKEN&" ");
SPACING←SPACING+1;
GET_TOKEN;
IF ¬EQU(TOKEN,"(") THEN
ERROR(1104,"Need left paren here, continue will insert it.");
TOKEN←",";
WHILE EQU(TOKEN,",") DO
α
GET_TOKEN;
IF TYPE_OF_TOKEN=string_token THEN PRINT(dquote&TOKEN&dquote)
ELSE α
REJECT←TRUE;
P_EXP;
β;
GET_TOKEN;
IF ¬EQU(TOKEN,",") AND ¬EQU(TOKEN,";") AND ¬EQU(TOKEN,")") THEN
ERROR_REJECT(1103,"Illegal separator. Continue"&
" will try to insert reasonable separator.");
β;
IF ¬EQU(TOKEN,")") THEN
ERROR(1104,"Need right paren here, continue will insert it.");
SPACING←SPACING-1;
PRINT(")");
β;
β;
! P_statement execution starts here;
LABL←CHANGER_HEAD; ! USUALLY NULL EXCEPT WHEN INSIDE A CHANGER.;
CHANGER_HEAD←null; LABEL_TYPE←0; GET_TOKEN;
WHILE EQU(TOKEN,"COMMENT") DO
α GARB←READ(semicolon_A_break); GET_TOKEN; β;
TRY_AGAIN:
IF TYPE_OF_TOKEN=numeric_token
THEN F_STATE(0,1,"Statement can't begin with a scalar")
ELSE IF TYPE_OF_TOKEN=string_token
THEN F_STATE(0,2,"Statement can't begin with a string")
ELSE IF TYPE_OF_TOKEN=id_token
THEN
α RECORD_POINTER (ID_LIST) POINT;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(TOKEN,ID_LIST:NAME[POINT]) DO
POINT←ID_LIST:NEXT[POINT];
! ?????;IF POINT≠NULL AND ID_LIST:TYPE[POINT]>world_VALUE THEN
α
LABEL_TYPE←ID_LIST:TYPE[POINT];
IF ID_LIST:LABEL_USED[POINT] THEN
ERROR(22,"Label multiply defined.");
ID_LIST:LABEL_USED[POINT]←TRUE;
IF EQU(LABL,null)
THEN LABL←TOKEN&" "
ELSE ERROR(22,"Double label.");
GET_TOKEN;
IF ¬EQU(TOKEN,":") THEN
ERROR_REJECT(23,"Colon needed here. Continue will insert it.");
IF LABEL_TYPE=cm_label_VALUE THEN
α
GET_TOKEN;
REJECT←TRUE;
IF ¬EQU(TOKEN,"ON") THEN ERROR(45,"Label mismatch.");
β;
GET_TOKEN;
GO TO TRY_AGAIN;
β
ELSE IF POINT≠NULL AND ID_LIST:TYPE[POINT]≤trans_VALUE THEN
α STRING id, ID_TYPE,AS;
RECORD_POINTER(DIMENS_LIST) ID_U_DIMEN,ID_L_DIMEN;
id←TOKEN;
ID_TYPE←ID_LIST:TYPE[POINT];
ID_U_DIMEN←DIMEN_DEFS[ID_LIST:DIMEN_P[POINT]];
ID_L_DIMEN←DIMEN_DEFS2[ID_LIST:DIMEN_P[POINT]];
GET_TOKEN;
IF EQU(TOKEN,"←") THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,"←")
THEN α AS←"AS "; REJECT←TRUE; β
ELSE α AS←"PAS "; β;
PRINT("("&LABL&AS&id);
SPACING←SPACING+1;
P_EXP;
IF ID_TYPE≠EXP_TYPE THEN ERROR(121,"Type mismatch on assignment.");
IFC MSMCHECK THENC CHECK("assignment statement",ID_U_DIMEN,ID_L_DIMEN,UPPER_D,LOWER_D);
ENDC; SPACING←SPACING-1;
PRINT(")");
β
ELSE IF EQU(TOKEN,"<") THEN
α STRING TYPE_CLC,CLC_LAB; BOOLEAN TEMP; ! GAS FOUND;
GET_TOKEN;
TYPE_CLC←TOKEN;
IF EQU(TOKEN,"<") THEN
α
GET_TOKEN;
IF ¬EQU(TOKEN,"=") THEN
ERROR_REJECT(26,"Need = here. Continue will insert it.");
β
ELSE IF ¬EQU(TOKEN,"=") AND ¬EQU(TOKEN,"≠") THEN
F_STATE(0,27,"Bogus assignment.");
GET_TOKEN;
POINT←SYMBOL_TABLE[HASH(TOKEN,hasher)];
WHILE POINT≠NULL AND ¬EQU(ID_LIST:NAME[POINT],TOKEN) DO
POINT←ID_LIST:NEXT[POINT];
IF POINT≠NULL AND ID_LIST:TYPE[POINT]=clc_label_VALUE THEN
α
CLC_LAB←TOKEN;
GET_TOKEN;
IF ¬EQU(TOKEN,":") THEN
α
REJECT←TRUE;
TEMP←FALSE;
PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" "&CLC_LAB&")");
β
ELSE TEMP←TRUE;
β
ELSE α
REJECT←TRUE;
CLC_LAB←T_GEN;
TEMP←TRUE;
PRINT("(CLCLAB "&CLC_LAB&")");
β;
IF TEMP THEN
α
PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" ("&CLC_LAB&" CLC");
SPACING←SPACING+1;
P_EXP;
SPACING←SPACING-1;
PRINT("))");
β;
β;
β
ELSE IF POINT=NULL THEN F_STATE (0,24,"Undefined ID.")
ELSE F_STATE(0,25,"Can't start statement this way.");
β
ELSE IF ¬(statement_beg ≤ TYPE_OF_RES_WORD ≤ statement_end) THEN
F_STATE(0,3,"Statement can't begin with <"&TOKEN&">")
ELSE CASE TYPE_OF_RES_WORD - statement_beg OF
α
redefine xx(str)=[redefine xx_temp="str" & "_P"; xx_temp;];
statement_definitions;
β;
FLUSH:
β "P_STATEMENT";
procedure process_switches(record_pointer(file) F);
α record_pointer(file_switch) swt;
swt ← file:switches[F];
while swt≠null_record do
α integer i;
for i ← 0 step 1 until switch_max do
if equ(file_switch:name[swt], switch_name[i])
then α switch_setting[i] ← true; done β;
if i > switch_max then
outstr("""" & file_switch:name[swt] & """ unknown switch"& crlf);
swt ← file_switch:next[swt]
β
β;
boolean procedure got_input(record_pointer(file) F);
α
if file:chn[F] < 0 then file:chn[F] ← getchan;
open(file:chn[F], file:device[F], file:mode[F], file:in_bfrs[F],
file:out_bfrs[F], count, brchar, eof);
if eof then
α release(file:chn[F]); file:chn[F] ← -1; return(false) β;
infile ← make_file_name(F);
lookup(file:chn[F], infile, eof);
if eof ∧ length(file:ext[F])=0 ∧ length(file:def_ext[f])≠0 then
α "try default"
file:ext[F] ← file:def_ext[F];
infile ← make_file_name(F);
lookup(file:chn[F], infile, eof);
β "try default";
process_switches(F);
return(¬eof)
β;
boolean procedure got_output(record_pointer(file) F);
α
string filename;
if file:chn[F] < 0 then file:chn[F] ← getchan;
open(file:chn[F], file:device[F], file:mode[F], file:in_bfrs[F],
file:out_bfrs[F], count, brchar, eof);
if eof then
α release(file:chn[F]); file:chn[F] ← -1; return(false) β;
if length(file:ext[F])=0 then file:ext[F] ← file:def_ext[F];
filename ← make_file_name(F);
enter(file:chn[F], filename, file:eof[F]); process_switches(F);
return(¬eof)
β;
! execution starts here;
α "execution"
COUNT ← 1000; DELIMITER_1 ← DELIMITER_2 ← 0; top_delimiters ← null_record;
TABLE1 ← ",.;:[](){}+-*/#∧∨¬⊗&≤≥<>≠=←↑→?|" & lf & cr & dquote & tab & ff & space;
SETBREAK(
word_R_break ← getbreak, TABLE1, NULL, "INRK");
SETBREAK(
non_blank_break ← getbreak, space & crlf & ff & tab, NULL, "XNRK");
SETBREAK(
word_S_break ← getbreak, TABLE1, NULL, "INSK");
SETBREAK(
close_brace_break← getbreak, "}", NULL, "ISK");
SETBREAK(
non_digit_break ← getbreak, ".0123456789", NULL, "XRK");
SETBREAK(
quote_break ← getbreak, dquote, NULL, "ISN");
SETBREAK(
semicolon_A_break← getbreak, ";", NULL, "IAK");
SETBREAK(
cr_break ← getbreak, cr, NULL, "IANK");
SETBREAK(
paren_cr_break ← getbreak, "()" & cr, NULL, "IANK");
SETBREAK(
lf_ff_break ← getbreak, lf & ff, NULL, "IANK");
SETBREAK(
semicolon_R_break ← getbreak, ";", NULL, "IRK");
SETBREAK(
omit_break ← getbreak, NULL, ";,." & ff & crlf, "I");
macro_delimiter_break ← getbreak;
DISTANCE_DIMENS←NEW_RECORD(DIMENS_LIST);
DIMENS_LIST:VALUE[DISTANCE_DIMENS]←1;
ANGLE_DIMENS←NEW_RECORD(DIMENS_LIST);
DIMENS_LIST:VALUE[ANGLE_DIMENS]←4;
TTYUP(TRUE);
! set up input and output;
if rpgsw then
α
cmd_line ← tmpin("AL", eof);
if eof
then α usererr(0, 1, "TMPIN lost"); rpgsw ← false β
else outstr(crlf & "AL: ");
β;
if ¬rpgsw then α outstr(crlf & "*"); cmd_line ← instrl(cr) β;
BIN_file ← new_record(file); ALL_file ← new_record(file);
SEX_file ← new_record(file); T←TRUE;
while true do
α "command" define want_BAIL=[switch_setting[b_X]];
want_BAIL ← false;
if ¬T then α outstr(crlf & "*"); cmd_line ← instrl(cr) β; T ← false;
AL_file ← scan_command(cmd_line, BIN_file, ALL_file);
if file:eof[AL_file] then
α usererr(0, 1, "null input spec"); continue "command" β;
! there was a special check for input named "DISPLAY" ;
file:mode[AL_file] ← 0; file:in_bfrs[AL_file] ← 12; file:out_bfrs[AL_file] ← 0;
file:def_ext[AL_file] ← "AL";
if ¬got_input(AL_file) then
α outstr(infile & "file not found"); continue "command" β;
copy_file_record(SEX_file, BIN_file);
file:mode[SEX_file] ← 0; file:in_bfrs[SEX_file] ← 0;
file:out_bfrs[SEX_file] ← 12; file:ext[SEX_file] ← "SEX";
if file:eof[SEX_file] then
α "null output spec"
file:device[SEX_file] ← "DSK";
file:name[SEX_file] ← file:name[AL_file]
β "null output spec";
if ¬got_output(SEX_file) then
α usererr(0, 1, "can't get output"); continue "command" β;
outfile←make_file_name(SEX_file);
chanin ← file:chn[AL_file]; chanout ← file:chn[SEX_file];
pagenum ← linenum ← sourcelvl ← 0; outstr(infile & " 1");
typed_page_num ← true;
ifc debug_compile thenc if want_BAIL then BAIL; endc
done "command"
β "command";
! set up predefined constants and variables;
FOR I←1 STEP 1 UNTIL const_count DO
α RECORD_POINTER (ID_LIST) TEMP; INTEGER INDEX;
TEMP←NEW_RECORD(ID_LIST);
ID_LIST:NAME[TEMP]←PRECONST[I];
ID_LIST:TYPE[TEMP]←PRECONST_TYPE[I];
ID_LIST:DIMEN_P[TEMP]←PRE_DIMENS[I];
INDEX←HASH(PRECONST[I],hasher);
ID_LIST:NEXT[TEMP]←SYMBOL_TABLE[INDEX];
SYMBOL_TABLE[INDEX]←TEMP;
β;
! SET UP PREDEFINED DIMENSIONS;
FOR I←1 STEP 1 UNTIL (dimen_num ← metric_max) DO
DIMENS_LIST:VALUE[DIMEN_DEFS[I] ← NEW_RECORD(DIMENS_LIST)] ← I;
! PARSE PROGRAM;
spacing ← 0; print("(PR"); SPACING ← 1; BLOCK_LEVEL←0;
! **********; P_STATEMENT; ! **********;
IF TOP_SOURCE≠NULL_RECORD OR ¬EQU(INPUT(CHANIN,omit_break),null) THEN
ERROR(200,"Misc. garbage found after last end.");
spacing ← 0; print(")");
! CLEAN UP;
IF CHANIN≠-1 THEN RELEASE(CHANIN);
WHILE TOP_SOURCE≠NULL DO
α
IF SOURCE_LIST:CHAN[TOP_SOURCE]≠-1 THEN RELEASE(SOURCE_LIST:CHAN[TOP_SOURCE]);
TOP_SOURCE←SOURCE_LIST:NEXT[TOP_SOURCE];
β;
CLOSO(CHANOUT);
CLOSO(CHANLOG);
β "execution";
α "swap" integer array swap[0:10]; string s; integer tmperr;
if length(file:ext[BIN_file])=0 then file:ext[BIN_file] ← "BIN";
s ← make_file_name(BIN_file) & "," & make_file_name(ALL_file) & "←" & outfile;
α "switches_for_ALC" boolean seen_one; integer i;
seen_one ← false;
for i ← 0 step 1 until switch_max do
if switch_setting[i] then
α
if ¬seen_one then α s ← s & "("; seen_one ← true β;
s ← s & switch_name[i];
β;
if seen_one then s ← s & ")";
β "switches_for_ALC";
tmpout("ALC", s, tmperr);
if tmperr then usererr(0, 1, "Trouble with TMPOUT");
outstr(crlf);
swap[0] ← cvsix("DSK"); swap[1] ← cvfil("ALC.DMP[HAL,HE]", swap[2], swap[4]);
swap[3] ← 1; ! start job in RPG mode; swap[5] ← 0;
call(location(swap[0]), "SWAP");
β "swap";
β "hidden_parse";
hidden_parse;
END "PARSE";